Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix transactions not being rolled back when the individual statements succeed, but the committing the transaction fails. #426

Merged
merged 1 commit into from
Sep 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SQLite/Core/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,11 @@ public final class Connection {
try self.run(begin)
do {
try block()
try self.run(commit)
} catch {
try self.run(rollback)
throw error
}
try self.run(commit)
}
}

Expand Down
27 changes: 27 additions & 0 deletions SQLiteTests/ConnectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,33 @@ class ConnectionTests : SQLiteTestCase {
AssertSQL("ROLLBACK TRANSACTION", 0)
}

func test_transaction_rollsBackTransactionsIfCommitsFail() {
// This test case needs to emulate an environment where the individual statements succeed, but committing the
// transactuin fails. Using deferred foreign keys is one option to achieve this.
try! db.execute("PRAGMA foreign_keys = ON;")
try! db.execute("PRAGMA defer_foreign_keys = ON;")
let stmt = try! db.prepare("INSERT INTO users (email, manager_id) VALUES (?, ?)", "alice@example.com", 100)

do {
try db.transaction {
try stmt.run()
}
} catch {
}

AssertSQL("BEGIN DEFERRED TRANSACTION")
AssertSQL("INSERT INTO users (email, manager_id) VALUES ('alice@example.com', 100)")
AssertSQL("COMMIT TRANSACTION")
AssertSQL("ROLLBACK TRANSACTION")

// Run another transaction to ensure that a subsequent transaction does not fail with an "cannot start a
// transaction within a transaction" error.
let stmt2 = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")
try! db.transaction {
try stmt2.run()
}
}

func test_transaction_beginsAndRollsTransactionsBack() {
let stmt = try! db.prepare("INSERT INTO users (email) VALUES (?)", "alice@example.com")

Expand Down