Skip to content

Commit

Permalink
Fixes #55
Browse files Browse the repository at this point in the history
  • Loading branch information
groue committed May 21, 2016
1 parent 997a29e commit 9794b72
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 72 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Release Notes

- The Record class no longer adopts CustomStringConvertible. This frees the `description` identifier for your record properties. Fixes [#58](https://github.com/groue/GRDB.swift/issues/58).

- Several database connections can now be used at the same time: you can move values from one database to another. Fixes [#55](https://github.com/groue/GRDB.swift/issues/55).


**Breaking Changes**

- The maximum number of reader connections in a database pool is now configured in a Configuration object.
Expand Down
32 changes: 32 additions & 0 deletions GRDB.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,16 @@
569531351C919DF200CF1A2B /* DatabasePoolCollationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569531331C919DF200CF1A2B /* DatabasePoolCollationTests.swift */; };
569531371C919DF700CF1A2B /* DatabasePoolFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569531361C919DF700CF1A2B /* DatabasePoolFunctionTests.swift */; };
569531381C919DF700CF1A2B /* DatabasePoolFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569531361C919DF700CF1A2B /* DatabasePoolFunctionTests.swift */; };
569C1EAC1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */; };
569C1EAD1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */; };
569C1EAE1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */; };
569C1EAF1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */; };
569C1EB21CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
569C1EB31CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
569C1EB41CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
569C1EB51CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
569C1EB61CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
569C1EB71CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */; };
56A238371B9C74A90082EB20 /* DatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A238131B9C74A90082EB20 /* DatabaseTests.swift */; };
56A238381B9C74A90082EB20 /* DatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A238131B9C74A90082EB20 /* DatabaseTests.swift */; };
56A238391B9C74A90082EB20 /* InMemoryDatabaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A238141B9C74A90082EB20 /* InMemoryDatabaseTests.swift */; };
Expand Down Expand Up @@ -916,6 +926,8 @@
569531281C908A5B00CF1A2B /* DatabasePoolSchemaCacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolSchemaCacheTests.swift; sourceTree = "<group>"; };
569531331C919DF200CF1A2B /* DatabasePoolCollationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolCollationTests.swift; sourceTree = "<group>"; };
569531361C919DF700CF1A2B /* DatabasePoolFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePoolFunctionTests.swift; sourceTree = "<group>"; };
569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseScheduler.swift; sourceTree = "<group>"; };
569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseSchedulerTests.swift; sourceTree = "<group>"; };
56A238131B9C74A90082EB20 /* DatabaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseTests.swift; sourceTree = "<group>"; };
56A238141B9C74A90082EB20 /* InMemoryDatabaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InMemoryDatabaseTests.swift; sourceTree = "<group>"; };
56A238161B9C74A90082EB20 /* DatabaseErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseErrorTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1349,6 +1361,14 @@
path = Public;
sourceTree = "<group>";
};
569C1EB01CF07DC80042627B /* DatabaseScheduler */ = {
isa = PBXGroup;
children = (
569C1EB11CF07DDD0042627B /* DatabaseSchedulerTests.swift */,
);
path = DatabaseScheduler;
sourceTree = "<group>";
};
56A238111B9C74A90082EB20 /* Core */ = {
isa = PBXGroup;
children = (
Expand All @@ -1357,6 +1377,7 @@
56A238151B9C74A90082EB20 /* DatabaseError */,
560A37A91C90084600949E71 /* DatabasePool */,
563363BB1C93FD32000BE133 /* DatabaseQueue */,
569C1EB01CF07DC80042627B /* DatabaseScheduler */,
560B3FA41C19DFF800C58EC7 /* Persistable */,
56EA86921C91DFDA002BB4DF /* DatabaseReader */,
56A238171B9C74A90082EB20 /* DatabaseValue */,
Expand Down Expand Up @@ -1467,6 +1488,7 @@
56A238731B9C75030082EB20 /* DatabaseError.swift */,
560A37A31C8F625000949E71 /* DatabasePool.swift */,
56A238741B9C75030082EB20 /* DatabaseQueue.swift */,
569C1EAB1CF07CCA0042627B /* DatabaseScheduler.swift */,
563363BF1C942C04000BE133 /* DatabaseReader.swift */,
5695311E1C907A8C00CF1A2B /* DatabaseSchemaCache.swift */,
563363D71C95787F000BE133 /* DatabaseStore.swift */,
Expand Down Expand Up @@ -2227,6 +2249,7 @@
560FC52A1CB003810014AA8E /* DatabaseError.swift in Sources */,
560FC52B1CB003810014AA8E /* DatabaseValue.swift in Sources */,
560FC52C1CB003810014AA8E /* SQLOperator.swift in Sources */,
569C1EAD1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */,
560FC52D1CB003810014AA8E /* StatementArguments+Foundation.swift in Sources */,
560FC52E1CB003810014AA8E /* Record.swift in Sources */,
560FC52F1CB003810014AA8E /* DatabaseCoder.swift in Sources */,
Expand Down Expand Up @@ -2264,6 +2287,7 @@
560FC5621CB00B880014AA8E /* Record+QueryInterfaceRequestTests.swift in Sources */,
560FC5641CB00B880014AA8E /* DatabaseQueueConcurrencyTests.swift in Sources */,
560FC5B21CB031E30014AA8E /* SQLiteStatementConvertibleFetchTests.swift in Sources */,
569C1EB31CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
560FC5651CB00B880014AA8E /* PrimaryKeyNoneTests.swift in Sources */,
560FC5661CB00B880014AA8E /* MinimalPrimaryKeyRowIDTests.swift in Sources */,
560FC5671CB00B880014AA8E /* DictionaryRowTests.swift in Sources */,
Expand Down Expand Up @@ -2378,6 +2402,7 @@
567156311CB16729007DC145 /* RecordFetchTests.swift in Sources */,
567156321CB16729007DC145 /* DatabasePoolFunctionTests.swift in Sources */,
567156341CB16729007DC145 /* DetachedRowTests.swift in Sources */,
569C1EB41CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
567156351CB16729007DC145 /* DatabaseQueueSchemaCacheTests.swift in Sources */,
567156361CB16729007DC145 /* MetalRowTests.swift in Sources */,
567156371CB16729007DC145 /* PrimaryKeyMultipleTests.swift in Sources */,
Expand Down Expand Up @@ -2452,6 +2477,7 @@
56AFC9FF1CB1A8BB00F48B96 /* DatabaseValueConvertible.swift in Sources */,
56AFCA001CB1A8BB00F48B96 /* Record.swift in Sources */,
56AFCA011CB1A8BB00F48B96 /* SQLOperator.swift in Sources */,
569C1EAF1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */,
56AFCA021CB1A8BB00F48B96 /* StatementArguments+Foundation.swift in Sources */,
56AFCA031CB1A8BB00F48B96 /* TableMapping.swift in Sources */,
56AFCA041CB1A8BB00F48B96 /* DatabaseCoder.swift in Sources */,
Expand Down Expand Up @@ -2489,6 +2515,7 @@
56AFCA321CB1AA9900F48B96 /* DatabaseQueueConcurrencyTests.swift in Sources */,
56AFCA331CB1AA9900F48B96 /* MinimalPrimaryKeyRowIDTests.swift in Sources */,
56AFCA341CB1AA9900F48B96 /* DictionaryRowTests.swift in Sources */,
569C1EB61CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
56AFCA351CB1AA9900F48B96 /* DatabaseCoderTests.swift in Sources */,
56AFCA361CB1AA9900F48B96 /* CollationTests.swift in Sources */,
56AFCA371CB1AA9900F48B96 /* SQLiteStatementConvertibleFetchTests.swift in Sources */,
Expand Down Expand Up @@ -2587,6 +2614,7 @@
56AFCA9D1CB1ABC800F48B96 /* DetachedRowTests.swift in Sources */,
56AFCA9E1CB1ABC800F48B96 /* DatabaseQueueSchemaCacheTests.swift in Sources */,
56AFCA9F1CB1ABC800F48B96 /* PrimaryKeyMultipleTests.swift in Sources */,
569C1EB71CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
56AFCAA01CB1ABC800F48B96 /* MetalRowTests.swift in Sources */,
56AFCAA21CB1ABC800F48B96 /* StatementArgumentsTests.swift in Sources */,
56AFCAA31CB1ABC800F48B96 /* RecordInitializersTests.swift in Sources */,
Expand Down Expand Up @@ -2661,6 +2689,7 @@
560D92411C672C3E00F4F92B /* DatabaseValueConvertible.swift in Sources */,
56A238A51B9C753B0082EB20 /* Record.swift in Sources */,
5605F1921C6B1A8700235C62 /* SQLOperator.swift in Sources */,
569C1EAE1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */,
5605F1701C672E4000235C62 /* StatementArguments+Foundation.swift in Sources */,
560D924C1C672C4B00F4F92B /* TableMapping.swift in Sources */,
5605F15C1C672E4000235C62 /* DatabaseCoder.swift in Sources */,
Expand Down Expand Up @@ -2698,6 +2727,7 @@
563363BE1C93FD5E000BE133 /* DatabaseQueueConcurrencyTests.swift in Sources */,
56A238501B9C74A90082EB20 /* MinimalPrimaryKeyRowIDTests.swift in Sources */,
56A238461B9C74A90082EB20 /* DictionaryRowTests.swift in Sources */,
569C1EB51CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
56B7F4381BE4C11200E39BBF /* DatabaseCoderTests.swift in Sources */,
564A50C81BFF4B7F00B3A3A2 /* CollationTests.swift in Sources */,
56E8CE111BB4FE5B00828BEC /* SQLiteStatementConvertibleFetchTests.swift in Sources */,
Expand Down Expand Up @@ -2777,6 +2807,7 @@
563363BD1C93FD5E000BE133 /* DatabaseQueueConcurrencyTests.swift in Sources */,
56A238551B9C74A90082EB20 /* PrimaryKeyNoneTests.swift in Sources */,
56A2384F1B9C74A90082EB20 /* MinimalPrimaryKeyRowIDTests.swift in Sources */,
569C1EB21CF07DDD0042627B /* DatabaseSchedulerTests.swift in Sources */,
56A238451B9C74A90082EB20 /* DictionaryRowTests.swift in Sources */,
56A238491B9C74A90082EB20 /* SelectStatementTests.swift in Sources */,
56B7F4371BE4C11200E39BBF /* DatabaseCoderTests.swift in Sources */,
Expand Down Expand Up @@ -2869,6 +2900,7 @@
56A238811B9C75030082EB20 /* DatabaseError.swift in Sources */,
56A238851B9C75030082EB20 /* DatabaseValue.swift in Sources */,
5605F1911C6B1A8700235C62 /* SQLOperator.swift in Sources */,
569C1EAC1CF07CCA0042627B /* DatabaseScheduler.swift in Sources */,
5605F16F1C672E4000235C62 /* StatementArguments+Foundation.swift in Sources */,
56A238A41B9C753B0082EB20 /* Record.swift in Sources */,
5605F15B1C672E4000235C62 /* DatabaseCoder.swift in Sources */,
Expand Down
45 changes: 14 additions & 31 deletions GRDB/Core/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public final class Database {
///
/// For more detailed information, see https://www.sqlite.org/c3ref/last_insert_rowid.html
public var lastInsertedRowID: Int64 {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
return sqlite3_last_insert_rowid(sqliteConnection)
}

Expand All @@ -56,7 +56,7 @@ public final class Database {
///
/// For more detailed information, see https://www.sqlite.org/c3ref/changes.html
public var changesCount: Int {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
return Int(sqlite3_changes(sqliteConnection))
}

Expand All @@ -66,7 +66,7 @@ public final class Database {
///
/// For more detailed information, see https://www.sqlite.org/c3ref/total_changes.html
public var totalChangesCount: Int {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
return Int(sqlite3_total_changes(sqliteConnection))
}

Expand Down Expand Up @@ -97,10 +97,6 @@ public final class Database {
/// See setupBusyMode()
private var busyCallback: BusyCallback?

/// The value for the dispatch queue specific that holds the Database identity.
/// See preconditionValidQueue.
var dispatchQueueID: UnsafeMutablePointer<Void> = nil

init(path: String, configuration: Configuration, schemaCache: DatabaseSchemaCacheType) throws {
// See https://www.sqlite.org/c3ref/open.html
var sqliteConnection: SQLiteConnection = nil
Expand Down Expand Up @@ -135,10 +131,12 @@ public final class Database {
self.sqliteConnection = sqliteConnection

configuration.SQLiteConnectionDidOpen?()

// Setup trace first, so that all queries, including initialization queries, are traced.
}

/// This method must be called after database initialization
func setup() throws {
// Setup trace first, so that setup queries are traced.
setupTrace()

try setupForeignKeys()
setupBusyMode()
setupDefaultFunctions()
Expand All @@ -147,7 +145,7 @@ public final class Database {

private var isClosed: Bool = false
func close() {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
assert(!isClosed)

configuration.SQLiteConnectionWillClose?(sqliteConnection)
Expand Down Expand Up @@ -336,21 +334,6 @@ public enum BusyMode {
}


// =========================================================================
// MARK: - SerializedDatabase Support

extension Database {

/// The key for the dispatch queue specific that holds the Database identity.
/// See preconditionValidQueue.
static let dispatchQueueIDKey = unsafeBitCast(Database.self, UnsafePointer<Void>.self) // some unique pointer

func preconditionValidQueue(@autoclosure message: () -> String = "Database was not used on the correct thread.", file: StaticString = #file, line: UInt = #line) {
GRDBPrecondition(dispatchQueueID == nil || dispatchQueueID == dispatch_get_specific(Database.dispatchQueueIDKey), message, file: file, line: line)
}
}


// =========================================================================
// MARK: - Statements

Expand Down Expand Up @@ -427,7 +410,7 @@ extension Database {
/// - arguments: Optional statement arguments.
/// - throws: A DatabaseError whenever an SQLite error occurs.
public func execute(sql: String, arguments: StatementArguments? = nil) throws {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)

// The tricky part is to consume arguments as statements are executed.
//
Expand Down Expand Up @@ -782,7 +765,7 @@ extension Database {
/// You may need to clear the cache manually if the database schema is
/// modified by another connection.
public func clearSchemaCache() {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
schemaCache.clear()

// We also clear updateStatementCache and selectStatementCache despite
Expand All @@ -795,7 +778,7 @@ extension Database {

/// Returns whether a table exists.
public func tableExists(tableName: String) -> Bool {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)

// SQlite identifiers are case-insensitive, case-preserving (http://www.alberton.info/dbms_identifiers_and_case_sensitivity.html)
return Row.fetchOne(self,
Expand Down Expand Up @@ -1123,7 +1106,7 @@ extension Database {
/// The transaction observer is weakly referenced: it is not retained, and
/// stops getting notifications after it is deallocated.
public func addTransactionObserver(transactionObserver: TransactionObserverType) {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
transactionObservers.append(WeakTransactionObserver(transactionObserver))
if transactionObservers.count == 1 {
installTransactionObserverHooks()
Expand All @@ -1132,7 +1115,7 @@ extension Database {

/// Remove a transaction observer.
public func removeTransactionObserver(transactionObserver: TransactionObserverType) {
preconditionValidQueue()
DatabaseScheduler.preconditionValidQueue(self)
transactionObservers.removeFirst { $0.observer === transactionObserver }
if transactionObservers.isEmpty {
uninstallTransactionObserverHooks()
Expand Down
Loading

0 comments on commit 9794b72

Please sign in to comment.