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 transaction leak on early break/return #463

Merged
merged 2 commits into from Jun 15, 2022

Conversation

ejoubaud
Copy link
Contributor

@ejoubaud ejoubaud commented Jun 15, 2022

Having a return/break inside the Connection#transaction block would cause the transaction to neither commit nor rollback after its begin, effectively causing the transaction to remain open and leak into the next calls made to the connection and generating warnings: WARNING: there is already a transaction in progress.

That's because #transaction used rescue/else, and the else block won't get executed in case of early break/return.

Here's the problem:

irb(main):001:1* def transaction
irb(main):002:1*   p 'pre'
irb(main):003:1*   yield
irb(main):004:1*   p 'post'
irb(main):005:1* rescue
irb(main):006:1*   p 'rescue'
irb(main):007:1* else
irb(main):008:1*   p 'else'
irb(main):009:1* ensure
irb(main):010:1*   p 'ensure'
irb(main):011:0> end
=> :transaction
irb(main):012:1* transaction do
irb(main):013:1*   p 'in'
irb(main):014:1*   break
irb(main):015:0> end
"pre"
"in"
"ensure"
=> nil

Using ensure instead of rescue's else fixes the problem.

Having a return/break inside the Connection#transaction block would cause the transaction to neither commit nor rollback after its begin, effectively causing the transaction to remain open and leak into the next calls made to the connection.

That's because `#transaction` used `rescue/else`, and the `else` block won't get executed in case of early break/return.

Here's the problem:

```
irb(main):001:1* def transaction
irb(main):002:1*   p 'pre'
irb(main):003:1*   yield
irb(main):004:1*   p 'post'
irb(main):005:1* rescue
irb(main):006:1*   p 'rescue'
irb(main):007:1* else
irb(main):008:1*   p 'else'
irb(main):009:1* ensure
irb(main):010:1*   p 'ensure'
irb(main):011:0> end
=> :transaction
irb(main):012:1* transaction do
irb(main):013:1*   p 'in'
irb(main):014:1*   break
irb(main):015:0> end
"pre"
"in"
"ensure"
=> nil
```

Using `ensure` instead of `rescue`'s `else` fixes the problem.
Copy link
Collaborator

@larskanis larskanis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your investigation and this pull request!

@conn.exec( "CREATE TABLE pie ( flavor TEXT )" )

begin
res = @conn.transaction do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment and the one above are unnecessary. Could you please remove them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch thanks, removed in 48bc9b2

@larskanis larskanis merged commit 217536e into ged:master Jun 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants