From 3055e07ca255a14d3b6896f3aecb738501521417 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Mon, 20 Jan 2025 11:38:46 -0500 Subject: [PATCH] Add GRDB_SQLITE_INLINE and GRDB_PERFORMANCE_TESTS envrionment variables to control whether to use the new GRDBSQLiteDynamic module and enable performance tests --- Package.swift | 29 ++++++++++- Sources/GRDBSQLite/module.modulemap | 5 ++ Sources/GRDBSQLite/shim.h | 49 +++++++++++++++++++ .../SQLiteInterface.swift | 0 .../SQLiteThunk.swift | 0 .../SystemSQLiteInterface.swift | 0 .../GRDBPerformance/PerformanceTests.swift | 20 ++++---- 7 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 Sources/GRDBSQLite/module.modulemap create mode 100644 Sources/GRDBSQLite/shim.h rename Sources/{GRDBSQLite => GRDBSQLiteDynamic}/SQLiteInterface.swift (100%) rename Sources/{GRDBSQLite => GRDBSQLiteDynamic}/SQLiteThunk.swift (100%) rename Sources/{GRDBSQLite => GRDBSQLiteDynamic}/SystemSQLiteInterface.swift (100%) diff --git a/Package.swift b/Package.swift index 6d64819213..56d3715c31 100644 --- a/Package.swift +++ b/Package.swift @@ -27,6 +27,10 @@ if ProcessInfo.processInfo.environment["SPI_BUILDER"] == "1" { dependencies.append(.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")) } +// When enabled, the GRDBSQLite dependency will use the system SQLite3 +// rather than the new GRDBSQLiteDynamic target +let SQLiteInline = ProcessInfo.processInfo.environment["GRDB_SQLITE_INLINE"] == "1" + let package = Package( name: "GRDB", defaultLocalization: "en", // for tests @@ -43,8 +47,9 @@ let package = Package( ], dependencies: dependencies, targets: [ - .target( - name: "GRDBSQLite"), + SQLiteInline ? + .systemLibrary(name: "GRDBSQLite", providers: [.apt(["libsqlite3-dev"])]) : + .target(name:"GRDBSQLite", path: "Sources/GRDBSQLiteDynamic"), .target( name: "GRDB", dependencies: ["GRDBSQLite"], @@ -84,3 +89,23 @@ let package = Package( ], swiftLanguageModes: [.v6] ) + +// The GRDB_PERFORMANCE_TESTS environment variable enables +// the performance tests to be included in the package, which can be run with: +// GRDB_PERFORMANCE_TESTS=1 swift test --filter GRDBPerformanceTests +if ProcessInfo.processInfo.environment["GRDB_PERFORMANCE_TESTS"] == "1" { + package.targets.append( + Target.testTarget( + name: "GRDBPerformanceTests", + dependencies: ["GRDB"], + path: "Tests/Performance/GRDBPerformance", + cSettings: cSettings, + swiftSettings: swiftSettings + [ + // Tests still use the Swift 5 language mode. + .swiftLanguageMode(.v5), + .enableUpcomingFeature("InferSendableFromCaptures"), + .enableUpcomingFeature("GlobalActorIsolatedTypesUsability"), + ]) + ) +} + diff --git a/Sources/GRDBSQLite/module.modulemap b/Sources/GRDBSQLite/module.modulemap new file mode 100644 index 0000000000..95e4e886f9 --- /dev/null +++ b/Sources/GRDBSQLite/module.modulemap @@ -0,0 +1,5 @@ +module GRDBSQLite [system] { + header "shim.h" + link "sqlite3" + export * +} diff --git a/Sources/GRDBSQLite/shim.h b/Sources/GRDBSQLite/shim.h new file mode 100644 index 0000000000..8a10c34cdf --- /dev/null +++ b/Sources/GRDBSQLite/shim.h @@ -0,0 +1,49 @@ +#include + +typedef void(*_errorLogCallback)(void *pArg, int iErrCode, const char *zMsg); + +/// Wrapper around sqlite3_config(SQLITE_CONFIG_LOG, ...) which is a variadic +/// function that can't be used from Swift. +static inline void _registerErrorLogCallback(_errorLogCallback callback) { + sqlite3_config(SQLITE_CONFIG_LOG, callback, 0); +} + +#if SQLITE_VERSION_NUMBER >= 3029000 +/// Wrapper around sqlite3_db_config() which is a variadic function that can't +/// be used from Swift. +static inline void _disableDoubleQuotedStringLiterals(sqlite3 *db) { + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, (void *)0); + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, (void *)0); +} + +/// Wrapper around sqlite3_db_config() which is a variadic function that can't +/// be used from Swift. +static inline void _enableDoubleQuotedStringLiterals(sqlite3 *db) { + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 1, (void *)0); + sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 1, (void *)0); +} +#else +static inline void _disableDoubleQuotedStringLiterals(sqlite3 *db) { } +static inline void _enableDoubleQuotedStringLiterals(sqlite3 *db) { } +#endif + +// Expose APIs that are missing from system +#ifdef GRDB_SQLITE_ENABLE_PREUPDATE_HOOK +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* +); +SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_count(sqlite3 *); +SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); +SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +#endif /* GRDB_SQLITE_ENABLE_PREUPDATE_HOOK */ diff --git a/Sources/GRDBSQLite/SQLiteInterface.swift b/Sources/GRDBSQLiteDynamic/SQLiteInterface.swift similarity index 100% rename from Sources/GRDBSQLite/SQLiteInterface.swift rename to Sources/GRDBSQLiteDynamic/SQLiteInterface.swift diff --git a/Sources/GRDBSQLite/SQLiteThunk.swift b/Sources/GRDBSQLiteDynamic/SQLiteThunk.swift similarity index 100% rename from Sources/GRDBSQLite/SQLiteThunk.swift rename to Sources/GRDBSQLiteDynamic/SQLiteThunk.swift diff --git a/Sources/GRDBSQLite/SystemSQLiteInterface.swift b/Sources/GRDBSQLiteDynamic/SystemSQLiteInterface.swift similarity index 100% rename from Sources/GRDBSQLite/SystemSQLiteInterface.swift rename to Sources/GRDBSQLiteDynamic/SystemSQLiteInterface.swift diff --git a/Tests/Performance/GRDBPerformance/PerformanceTests.swift b/Tests/Performance/GRDBPerformance/PerformanceTests.swift index c9f4ac0bfa..d382570026 100644 --- a/Tests/Performance/GRDBPerformance/PerformanceTests.swift +++ b/Tests/Performance/GRDBPerformance/PerformanceTests.swift @@ -9,16 +9,16 @@ import RealmSwift // MARK:- SQLite let itemTable = Table("item") -let i0Column = Expression("i0") -let i1Column = Expression("i1") -let i2Column = Expression("i2") -let i3Column = Expression("i3") -let i4Column = Expression("i4") -let i5Column = Expression("i5") -let i6Column = Expression("i6") -let i7Column = Expression("i7") -let i8Column = Expression("i8") -let i9Column = Expression("i9") +let i0Column = SQLite.Expression("i0") +let i1Column = SQLite.Expression("i1") +let i2Column = SQLite.Expression("i2") +let i3Column = SQLite.Expression("i3") +let i4Column = SQLite.Expression("i4") +let i5Column = SQLite.Expression("i5") +let i6Column = SQLite.Expression("i6") +let i7Column = SQLite.Expression("i7") +let i8Column = SQLite.Expression("i8") +let i9Column = SQLite.Expression("i9") // MARK: - Realm