diff --git a/Sources/SQLyra/Database.swift b/Sources/SQLyra/Database.swift index de55912..cef1500 100644 --- a/Sources/SQLyra/Database.swift +++ b/Sources/SQLyra/Database.swift @@ -133,6 +133,6 @@ public final class Database: DatabaseHandle { public func prepare(_ sql: String) throws -> PreparedStatement { var stmt: OpaquePointer! try check(sqlite3_prepare_v2(db, sql, -1, &stmt, nil)) - return PreparedStatement(stmt: stmt) + return PreparedStatement(stmt: stmt, database: self) } } diff --git a/Sources/SQLyra/PreparedStatement.swift b/Sources/SQLyra/PreparedStatement.swift index 57bfd16..0887706 100644 --- a/Sources/SQLyra/PreparedStatement.swift +++ b/Sources/SQLyra/PreparedStatement.swift @@ -7,6 +7,7 @@ import SQLite3 /// Or, in other words, these routines are constructors for the prepared statement object. public final class PreparedStatement: DatabaseHandle { let stmt: OpaquePointer + let database: Database // release database after all statements /// Find the database handle of a prepared statement. var db: OpaquePointer! { sqlite3_db_handle(stmt) } @@ -17,8 +18,9 @@ public final class PreparedStatement: DatabaseHandle { } ) - init(stmt: OpaquePointer) { + init(stmt: OpaquePointer, database: Database) { self.stmt = stmt + self.database = database } deinit { diff --git a/Tests/SQLyraTests/PreparedStatementTests.swift b/Tests/SQLyraTests/PreparedStatementTests.swift index f75d3ec..a154699 100644 --- a/Tests/SQLyraTests/PreparedStatementTests.swift +++ b/Tests/SQLyraTests/PreparedStatementTests.swift @@ -114,4 +114,18 @@ struct PreparedStatementTests { """ #expect(df.description == expected + "\n") } + + @Test static func retainDatabase() throws { + weak var db: Database? + var statement: PreparedStatement? + do { + let suite = try PreparedStatementTests() + db = suite.db + statement = try suite.db.prepare("SELECT * FROM contacts;") + } + try #require(statement != nil) + #expect(db != nil) + statement = nil + #expect(db == nil) + } }