Skip to content

Commit

Permalink
Merge pull request #560 from larskanis/rollback
Browse files Browse the repository at this point in the history
Add PG::RollbackTransaction as an option to exit conn.transaction
  • Loading branch information
larskanis authored Jul 20, 2024
2 parents 98069ee + 3e9c143 commit 0508e25
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/pg/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,11 @@ 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
Expand Down
6 changes: 6 additions & 0 deletions lib/pg/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ class LostCopyState < PG::Error
class NotInBlockingMode < PG::Error
end

# PG::Connection#transaction uses this exception to distinguish a deliberate rollback from other exceptional situations.
# Normally, raising an exception will cause the .transaction method to rollback the database transaction and pass on the exception.
# But if you raise an PG::RollbackTransaction exception, then the database transaction will be rolled back, without passing on the exception.
class RollbackTransaction < StandardError
end

end # module PG

18 changes: 18 additions & 0 deletions spec/pg/connection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,24 @@
end
end

it "rolls back a transaction if a PG::RollbackTransaction exception is raised" do
# abort the per-example transaction so we can test our own
@conn.exec( 'ROLLBACK' )
@conn.exec( "CREATE TABLE pie ( flavor TEXT )" )

begin
@conn.transaction do
@conn.exec( "INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')" )
raise PG::RollbackTransaction
end

res = @conn.exec( "SELECT * FROM pie" )
expect( res.ntuples ).to eq( 0 )
ensure
@conn.exec( "DROP TABLE pie" )
end
end

it "commits even if the block includes an early break/return" do
# abort the per-example transaction so we can test our own
@conn.exec( 'ROLLBACK' )
Expand Down

0 comments on commit 0508e25

Please sign in to comment.