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

0.9.1 - #transaction may wrongly end enclosing transaction #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

pilcrow
Copy link
Member

@pilcrow pilcrow commented Jan 10, 2011

Issue

rdbi-0.9.1

RDBI::Database#transaction may incorrectly end the enclosing transaction at the conclusion of a nested transaction block, if the user has already explicitly COMMITted or ROLLBACKed the inner transaction.

Presently, #transaction, checks only to see that the dbh is within any transaction, so it cannot tell whether a block concludes in the same (possibly nested) transaction which it began.

The impact is likely limited, as nested transaction support (SAVEPOINTs?) is not to my knowledge implemented in any supported backend.

Example

Presuming a database with nested transaction support:
# initial tx depth -> 0

dbh.transaction do |dbh|    # implicit BEGIN
                            #   tx++ -> 1

  dbh.execute(SQL_1)

  dbh.transaction do |dbh|  # implicit BEGIN
                            #   tx++ -> 2
    dbh.execute(SQL_2)

    dbh.rollback            # explicit ROLLBACK:  SQL_2 undone
                            #   tx-- -> 1
  end                       # implicit COMMIT:  SQL_1 committed
                            #   ERROR - SQL_1 committed too early
                            #   tx-- -> 0

  dbh.execute(SQL_3)

  #dbh.commit               # ERROR - explicit COMMIT would be ignored here
end                         # ERROR - implicit COMMIT ignored, too
                            # ERROR - SQL_3 uncommitted

Proposed Fix

This pull request simply has #transaction remember its tx depth upon entry, and only #commit or #rollback if the depth is as expected after leaving the user block.

Tests

I have no tests for this fix.

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
@erikh
Copy link

erikh commented Jan 16, 2011

Ok; I'm gonna need tests for this one, for sure.

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.

2 participants