diff --git a/lib/pg/connection.rb b/lib/pg/connection.rb index eb607ab82..e45a851e8 100644 --- a/lib/pg/connection.rb +++ b/lib/pg/connection.rb @@ -306,22 +306,19 @@ class << self # and a +COMMIT+ at the end of the block, or # +ROLLBACK+ if any exception occurs. def transaction - rollback = false exec "BEGIN" yield(self) - rescue PG::RollbackTransaction - rollback = true - cancel if transaction_status == PG::PQTRANS_ACTIVE - block - exec "ROLLBACK" - rescue Exception - rollback = true - cancel if transaction_status == PG::PQTRANS_ACTIVE - block - exec "ROLLBACK" + rescue PG::RollbackTransaction => error + rescue Exception => error raise ensure - exec "COMMIT" unless rollback + if error || Thread.current.status == "aborting" + cancel if transaction_status == PG::PQTRANS_ACTIVE + block + exec("ROLLBACK") + else + exec("COMMIT") + end end ### Returns an array of Hashes with connection defaults. See ::conndefaults diff --git a/spec/pg/connection_spec.rb b/spec/pg/connection_spec.rb index 7763493a2..fdae1b2b7 100644 --- a/spec/pg/connection_spec.rb +++ b/spec/pg/connection_spec.rb @@ -1073,6 +1073,41 @@ end expect( res ).to eq( "transaction result" ) end + + context "when current thread gets halted in the middle of the running transaction" do + + it "rollbacks the transaction" do + # abort the per-example transaction so we can test our own + @conn.exec('ROLLBACK') + @conn.exec("CREATE TABLE pie ( flavor TEXT )") + + begin + q = Thread::Queue.new + thread = Thread.new do + conn = $pg_server.connect + conn.transaction do + conn.exec("INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')") + q << 1 + # emulate some load that keeps the transaction open + sleep 2 + end + ensure + conn&.close + end + # Wait for the thread to reach the testing point + q.pop + # Terminate the thread ungracefully and wait it to die + thread.exit + thread.join + + res = @conn.exec("SELECT * FROM pie") + expect(res.ntuples).to eq(0) + ensure + thread.exit + @conn.exec("DROP TABLE pie") + end + end + end end describe "large objects" do