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

Add PG::RollbackTransaction as an option to exit conn.transaction #560

Merged
merged 1 commit into from
Jul 20, 2024
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
5 changes: 5 additions & 0 deletions lib/pg/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,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 @@ -920,6 +920,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
Loading