Skip to content

Commit b866586

Browse files
authored
Add traits for SQLite compile options (#14)
* Add traits for SQLite compile options * Make more types Sendable * Wrap Connection in an @unchecked Sendable for test_concurrent_access_single_connection * Remove @unsafe Sendable from TestObject * Update tests and cleanup conditional imports * Add NonisolatedNonsendingByDefault * Add GlobalActorIsolatedTypesUsability and InferSendableFromCaptures * Change Result error parameter to a String so it can be Sendable * Make ForeignKeyError Sendable * Enable ENABLE_FTS3 and ENABLE_FTS4 traits by default * Do not include OMIT_SHARED_CACHE trait by default
1 parent 5185f4b commit b866586

36 files changed

+1031
-239
lines changed

Examples/PackageTraits/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,7 @@ let package = Package(
6464
The `SQLMiddleware` module has just a single top-level function `middlewareDatabaseType()` that will return either "SQLCipher <version>" or "SQLite3 <version>" depending on whether it was included with the "SQLCipher" trait.
6565

6666
```swift
67-
#if canImport(SQLCipher)
6867
import SQLCipher
69-
#else
70-
import SQLite3
71-
#endif
7268

7369
public func databaseVersion() -> String? {
7470
#if canImport(SQLCipher)

Package.swift

Lines changed: 305 additions & 46 deletions
Large diffs are not rendered by default.

[email protected]

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// swift-tools-version:5.9
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "swift-sqlcipher",
6+
platforms: [
7+
.iOS(.v13),
8+
.macOS(.v10_13),
9+
.watchOS(.v4),
10+
.tvOS(.v12),
11+
.visionOS(.v1)
12+
],
13+
products: [
14+
.library(
15+
name: "SQLiteDB",
16+
targets: ["SQLiteDB"]
17+
),
18+
.library(
19+
name: "SQLCipher",
20+
targets: ["SQLCipher"]
21+
)
22+
],
23+
targets: [
24+
.target(
25+
name: "SQLiteDB",
26+
dependencies: [.target(name: "SQLCipher")],
27+
cSettings: [.define("SQLITE_HAS_CODEC")]
28+
),
29+
.target(
30+
name: "SQLCipher",
31+
sources: ["sqlite", "libtomcrypt"],
32+
publicHeadersPath: "sqlite",
33+
cSettings: [
34+
.headerSearchPath("libtomcrypt/headers"),
35+
.define("SQLITE_DQS", to: "0"),
36+
.define("SQLITE_ENABLE_API_ARMOR"),
37+
.define("SQLITE_ENABLE_COLUMN_METADATA"),
38+
.define("SQLITE_ENABLE_DBSTAT_VTAB"),
39+
.define("SQLITE_ENABLE_FTS3"),
40+
.define("SQLITE_ENABLE_FTS3_PARENTHESIS"),
41+
.define("SQLITE_ENABLE_FTS3_TOKENIZER"),
42+
.define("SQLITE_ENABLE_FTS4"),
43+
.define("SQLITE_ENABLE_FTS5"),
44+
.define("SQLITE_ENABLE_MEMORY_MANAGEMENT"),
45+
.define("SQLITE_ENABLE_PREUPDATE_HOOK"),
46+
.define("SQLITE_ENABLE_RTREE"),
47+
.define("SQLITE_ENABLE_SESSION"),
48+
.define("SQLITE_ENABLE_STMTVTAB"),
49+
.define("SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION"),
50+
.define("SQLITE_ENABLE_UNLOCK_NOTIFY"),
51+
.define("SQLITE_MAX_VARIABLE_NUMBER", to: "250000"),
52+
.define("SQLITE_LIKE_DOESNT_MATCH_BLOBS"),
53+
.define("SQLITE_OMIT_DEPRECATED"),
54+
.define("SQLITE_OMIT_SHARED_CACHE"),
55+
.define("SQLITE_SECURE_DELETE"),
56+
.define("SQLITE_THREADSAFE", to: "2"),
57+
.define("SQLITE_USE_URI"),
58+
.define("SQLITE_ENABLE_SNAPSHOT"),
59+
.define("SQLITE_HAS_CODEC"),
60+
.define("SQLITE_HOMEGROWN_RECURSIVE_MUTEX"), // needed or we see hangs in test cases
61+
.define("SQLITE_TEMP_STORE", to: "2"),
62+
.define("SQLITE_EXTRA_INIT", to: "sqlcipher_extra_init"),
63+
.define("SQLITE_EXTRA_SHUTDOWN", to: "sqlcipher_extra_shutdown"),
64+
.define("HAVE_GETHOSTUUID", to: "0"),
65+
.define("HAVE_STDINT_H"),
66+
.define("SQLCIPHER_CRYPTO_LIBTOMCRYPT"),
67+
.define("SQLCIPHER_CRYPTO_CUSTOM", to: "sqlcipher_ltc_setup"),
68+
],
69+
linkerSettings: [.linkedLibrary("log", .when(platforms: [.android]))]),
70+
.testTarget(
71+
name: "SQLiteDBTests",
72+
dependencies: ["SQLiteDB"],
73+
resources: [.process("Resources")]
74+
)
75+
]
76+
)

Sources/SQLCipher/sqlite/sqlite3.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6661,7 +6661,7 @@ SQLITE_API int sqlite3_collation_needed16(
66616661
);
66626662

66636663
/* BEGIN SQLCIPHER */
6664-
#ifdef SQLITE_HAS_CODEC
6664+
//#ifdef SQLITE_HAS_CODEC
66656665
/*
66666666
** Specify the key for an encrypted database. This routine should be
66676667
** called right after sqlite3_open().
@@ -6717,7 +6717,7 @@ SQLITE_API int sqlite3_rekey_v2(
67176717
SQLITE_API void sqlite3_activate_see(
67186718
const char *zPassPhrase /* Activation phrase */
67196719
);
6720-
#endif
6720+
//#endif
67216721
/* END SQLCIPHER */
67226722

67236723
#ifdef SQLITE_ENABLE_CEROD

Sources/SQLiteDB/Core/Backup.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,7 @@
2424

2525
import Foundation
2626
import Dispatch
27-
#if SQLITE_SWIFT_STANDALONE
28-
import sqlite3
29-
#elseif SQLITE_SWIFT_SQLCIPHER
3027
import SQLCipher
31-
#elseif os(Linux) || os(Windows) || os(Android)
32-
import CSQLite
33-
#else
34-
import SQLite3
35-
#endif
3628

3729
/// An object representing database backup.
3830
///

Sources/SQLiteDB/Core/Blob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// THE SOFTWARE.
2323
//
2424

25-
public struct Blob {
25+
public struct Blob: Sendable {
2626

2727
public let bytes: [UInt8]
2828

Sources/SQLiteDB/Core/Connection+Aggregation.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import Foundation
2-
#if SQLITE_SWIFT_STANDALONE
3-
import sqlite3
4-
#elseif SQLITE_SWIFT_SQLCIPHER
52
import SQLCipher
6-
#elseif os(Linux) || os(Windows) || os(Android)
7-
import CSQLite
8-
#else
9-
import SQLite3
10-
#endif
113

124
extension Connection {
135
private typealias Aggregate = @convention(block) (Int, Context, Int32, Argv) -> Void

Sources/SQLiteDB/Core/Connection+Attach.swift

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
11
import Foundation
2-
#if SQLITE_SWIFT_STANDALONE
3-
import sqlite3
4-
#elseif SQLITE_SWIFT_SQLCIPHER
52
import SQLCipher
6-
#elseif os(Linux) || os(Windows) || os(Android)
7-
import CSQLite
8-
#else
9-
import SQLite3
10-
#endif
113

124
extension Connection {
13-
#if SQLITE_SWIFT_SQLCIPHER
145
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#attach
156
public func attach(_ location: Location, as schemaName: String, key: String? = nil) throws {
167
if let key {
@@ -19,12 +10,6 @@ extension Connection {
1910
try run("ATTACH DATABASE ? AS ?", location.description, schemaName)
2011
}
2112
}
22-
#else
23-
/// See https://www3.sqlite.org/lang_attach.html
24-
public func attach(_ location: Location, as schemaName: String) throws {
25-
try run("ATTACH DATABASE ? AS ?", location.description, schemaName)
26-
}
27-
#endif
2813

2914
/// See https://www3.sqlite.org/lang_detach.html
3015
public func detach(_ schemaName: String) throws {

Sources/SQLiteDB/Core/Connection.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,7 @@
2424

2525
import Foundation
2626
import Dispatch
27-
#if SQLITE_SWIFT_STANDALONE
28-
import sqlite3
29-
#elseif SQLITE_SWIFT_SQLCIPHER
3027
import SQLCipher
31-
#elseif os(Linux) || os(Windows) || os(Android)
32-
import CSQLite
33-
#else
34-
import SQLite3
35-
#endif
3628

3729
/// A connection to SQLite.
3830
public final class Connection {

Sources/SQLiteDB/Core/Result.swift

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
#if SQLITE_SWIFT_STANDALONE
2-
import sqlite3
3-
#elseif SQLITE_SWIFT_SQLCIPHER
41
import SQLCipher
5-
#elseif os(Linux) || os(Windows) || os(Android)
6-
import CSQLite
7-
#else
8-
import SQLite3
9-
#endif
102

113
public enum Result: Error {
124

@@ -19,7 +11,7 @@ public enum Result: Error {
1911
/// - code: SQLite [error code](https://sqlite.org/rescode.html#primary_result_code_list)
2012
///
2113
/// - statement: the statement which produced the error
22-
case error(message: String, code: Int32, statement: Statement?)
14+
case error(message: String, code: Int32, statement: String?)
2315

2416
/// Represents a SQLite specific [extended error code] (https://sqlite.org/rescode.html#primary_result_codes_versus_extended_result_codes)
2517
///
@@ -28,20 +20,20 @@ public enum Result: Error {
2820
/// - extendedCode: SQLite [extended error code](https://sqlite.org/rescode.html#extended_result_code_list)
2921
///
3022
/// - statement: the statement which produced the error
31-
case extendedError(message: String, extendedCode: Int32, statement: Statement?)
23+
case extendedError(message: String, extendedCode: Int32, statement: String?)
3224

3325
init?(errorCode: Int32, connection: Connection, statement: Statement? = nil) {
3426
guard !Result.successCodes.contains(errorCode) else { return nil }
3527

3628
let message = String(cString: sqlite3_errmsg(connection.handle))
3729

3830
guard connection.usesExtendedErrorCodes else {
39-
self = .error(message: message, code: errorCode, statement: statement)
31+
self = .error(message: message, code: errorCode, statement: statement?.description)
4032
return
4133
}
4234

4335
let extendedErrorCode = sqlite3_extended_errcode(connection.handle)
44-
self = .extendedError(message: message, extendedCode: extendedErrorCode, statement: statement)
36+
self = .extendedError(message: message, extendedCode: extendedErrorCode, statement: statement?.description)
4537
}
4638

4739
}

0 commit comments

Comments
 (0)