Skip to content

Commit 0a35c18

Browse files
committed
Fix transactions not being rolled back when the individual statements succeed, but the committing the transaction fails.
1 parent d93f37b commit 0a35c18

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

SQLite/Core/Connection.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,11 @@ public final class Connection {
328328
try self.run(begin)
329329
do {
330330
try block()
331+
try self.run(commit)
331332
} catch {
332333
try self.run(rollback)
333334
throw error
334335
}
335-
try self.run(commit)
336336
}
337337
}
338338

SQLiteTests/ConnectionTests.swift

+27
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,33 @@ class ConnectionTests : SQLiteTestCase {
125125
AssertSQL("ROLLBACK TRANSACTION", 0)
126126
}
127127

128+
func test_transaction_rollsBackTransactionsIfCommitsFail() {
129+
// This test case needs to emulate an environment where the individual statements succeed, but committing the
130+
// transactuin fails. Using deferred foreign keys is one option to achieve this.
131+
try! db.execute("PRAGMA foreign_keys = ON;")
132+
try! db.execute("PRAGMA defer_foreign_keys = ON;")
133+
let stmt = try! db.prepare("INSERT INTO users (email, manager_id) VALUES (?, ?)", "alice@example.com", 100)
134+
135+
do {
136+
try db.transaction {
137+
try stmt.run()
138+
}
139+
} catch {
140+
}
141+
142+
AssertSQL("BEGIN DEFERRED TRANSACTION")
143+
AssertSQL("INSERT INTO users (email, manager_id) VALUES ('alice@example.com', 100)")
144+
AssertSQL("COMMIT TRANSACTION")
145+
AssertSQL("ROLLBACK TRANSACTION")
146+
147+
// Run another transaction to ensure that a subsequent transaction does not fail with an "cannot start a
148+
// transaction within a transaction" error.
149+
let stmt2 = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
150+
try! db.transaction {
151+
try stmt2.run()
152+
}
153+
}
154+
128155
func test_transaction_beginsAndRollsTransactionsBack() {
129156
let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
130157

0 commit comments

Comments
 (0)