Skip to content

Commit a8b31a9

Browse files
committed
fix: release rolled-back savepoints
1 parent ccaae3d commit a8b31a9

2 files changed

Lines changed: 33 additions & 4 deletions

File tree

Sources/SQLite/Core/Connection.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,17 +429,27 @@ public final class Connection {
429429
let name = name.quote("'")
430430
let savepoint = "SAVEPOINT \(name)"
431431

432-
try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)")
432+
try transaction(
433+
savepoint,
434+
block,
435+
"RELEASE \(savepoint)",
436+
or: "ROLLBACK TO \(savepoint)",
437+
followedBy: "RELEASE \(savepoint)"
438+
)
433439
}
434440

435-
fileprivate func transaction(_ begin: String, _ block: () throws -> Void, _ commit: String, or rollback: String) throws {
441+
fileprivate func transaction(_ begin: String, _ block: () throws -> Void, _ commit: String,
442+
or rollback: String, followedBy cleanup: String? = nil) throws {
436443
return try sync {
437444
try self.run(begin)
438445
do {
439446
try block()
440447
try self.run(commit)
441448
} catch {
442449
try self.run(rollback)
450+
if let cleanup {
451+
try self.run(cleanup)
452+
}
443453
throw error
444454
}
445455
}

Tests/SQLiteTests/Core/ConnectionTests.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,27 @@ class ConnectionTests: SQLiteTestCase {
315315
assertSQL("INSERT INTO users (email) VALUES ('alice@example.com')", 2)
316316
assertSQL("ROLLBACK TO SAVEPOINT '2'")
317317
assertSQL("ROLLBACK TO SAVEPOINT '1'")
318-
assertSQL("RELEASE SAVEPOINT '2'", 0)
319-
assertSQL("RELEASE SAVEPOINT '1'", 0)
318+
assertSQL("RELEASE SAVEPOINT '2'")
319+
assertSQL("RELEASE SAVEPOINT '1'")
320+
}
321+
322+
func test_savepoint_releasesAfterRollback() throws {
323+
let rollbackError = NSError(domain: "com.stephencelis.SQLiteTests", code: 1, userInfo: nil)
324+
325+
XCTAssertThrowsError(try db.savepoint("1") {
326+
try db.run("INSERT INTO users (email) VALUES (?)", "alice@example.com")
327+
throw rollbackError
328+
}) { error in
329+
let error = error as NSError
330+
XCTAssertEqual(rollbackError.domain, error.domain)
331+
XCTAssertEqual(rollbackError.code, error.code)
332+
}
333+
334+
XCTAssertEqual(0, try db.scalar(users.count))
335+
try db.transaction {
336+
try db.run("INSERT INTO users (email) VALUES (?)", "alice@example.com")
337+
}
338+
XCTAssertEqual(1, try db.scalar(users.count))
320339
}
321340

322341
func test_updateHook_setsUpdateHook_withInsert() throws {

0 commit comments

Comments
 (0)