From a1ef4503bc8b41e9fd1e9f2403d0517bf98b4005 Mon Sep 17 00:00:00 2001 From: pilcrow Date: Mon, 10 Jan 2011 11:21:22 -0600 Subject: [PATCH] Make #transaction check nested tx depth before implicit COMMIT/ROLLBACK. Previously, #transaction only checked to see that it was inside *any* tx before ending (COMMIT/ROLLBACK) the open tx. However, the ability of users to explicitly end a tx inside the block means that the #transaction block might end in an enclosing tx wherein the implicit COMMIT/ROLLBACK behavior intended for the *nested* transaction is incorrect. Example: dbh.transaction do |dbh| # tx depth 1 dbh.execute(STMT_1) dbh.transaction do |dbh| # tx depth 2 dbh.execute(STMT_2) dbh.commit # tx depth 1 (#rollback would do the same) end # tx depth 0 (implicit COMMIT -- to early) dbh.execute(STMT_3) end # implicit COMMIT of STMT_3 ignored! # explicit would have been ignored, too --- lib/rdbi/database.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/rdbi/database.rb b/lib/rdbi/database.rb index 7f1f990..72e4630 100644 --- a/lib/rdbi/database.rb +++ b/lib/rdbi/database.rb @@ -125,12 +125,15 @@ def disconnect # for you. # def transaction(&block) - @in_transaction += 1 + transaction_depth = (@in_transaction += 1) + begin yield self - self.commit if @in_transaction > 0 + # Only commit if user didn't already explicitly end the transaction + self.commit if @in_transaction == transaction_depth rescue => e - self.rollback + # Only rollback if user didn't already explicitly end the transaction + self.rollback if @in_transaction == transaction_depth raise e ensure @in_transaction -= 1 unless @in_transaction == 0