module ActiveRecord module ConnectionAdapters module Sqlserver module CoreExt module DatabaseStatements # This is a copy of the current (3.1.3) ActiveRecord's transaction method. We should propose # a patch to the default transaction method to make it more callback for adapters that want to # do deadlock retry logic. Because this is a copy, we really need to keep an eye out on this when # upgradding the adapter. def transaction_with_retry_deadlock_victim(options = {}) options.assert_valid_keys :requires_new, :joinable last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil if options.has_key?(:joinable) @transaction_joinable = options[:joinable] else @transaction_joinable = true end requires_new = options[:requires_new] || !last_transaction_joinable transaction_open = false @_current_transaction_records ||= [] begin if block_given? if requires_new || open_transactions == 0 if open_transactions == 0 begin_db_transaction elsif requires_new create_savepoint end increment_open_transactions transaction_open = true @_current_transaction_records.push([]) end yield end rescue Exception => database_transaction_rollback if transaction_open && !outside_transaction? transaction_open = false decrement_open_transactions # handle deadlock victim retries at the outermost transaction if open_transactions == 0 if database_transaction_rollback.is_a?(::ActiveRecord::DeadlockVictim) # SQL Server has already rolled back, so rollback activerecord's history rollback_transaction_records(true) retry else rollback_db_transaction rollback_transaction_records(true) end else rollback_to_savepoint rollback_transaction_records(false) end end raise unless database_transaction_rollback.is_a?(::ActiveRecord::Rollback) end ensure @transaction_joinable = last_transaction_joinable if outside_transaction? @open_transactions = 0 elsif transaction_open decrement_open_transactions begin if open_transactions == 0 commit_db_transaction commit_transaction_records else release_savepoint save_point_records = @_current_transaction_records.pop unless save_point_records.blank? @_current_transaction_records.push([]) if @_current_transaction_records.empty? @_current_transaction_records.last.concat(save_point_records) end end rescue Exception => database_transaction_rollback if open_transactions == 0 rollback_db_transaction rollback_transaction_records(true) else rollback_to_savepoint rollback_transaction_records(false) end raise end end end end end end end end