From fb2325e35855d62abd2c76ce03feaa3ca7992e4f Mon Sep 17 00:00:00 2001 From: "Hongli Lai (Phusion)" Date: Thu, 9 Oct 2008 17:57:49 +0200 Subject: Reimplement Jeremy's PostgreSQL automatic transaction state introspection code. - Fixed compatibility with the old 'postgres' driver which doesn't support transaction state introspection. - Added unit tests for it. --- .../abstract/database_statements.rb | 20 ++++++++++++++++++-- .../connection_adapters/postgresql_adapter.rb | 10 ++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index bd434f2efc..a9a63e5a9f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -53,6 +53,20 @@ module ActiveRecord def delete(sql, name = nil) delete_sql(sql, name) end + + # Checks whether there is currently no transaction active. This is done + # by querying the database driver, and does not use the transaction + # house-keeping information recorded by #increment_open_transactions and + # friends. + # + # Returns true if there is no transaction active, false if there is a + # transaction active, and nil if this information is unknown. + # + # Not all adapters supports transaction state introspection. Currently, + # only the PostgreSQL adapter supports this. + def outside_transaction? + nil + end # Runs the given block in a database transaction, and returns the result # of the block. @@ -119,7 +133,7 @@ module ActiveRecord yield end rescue Exception => database_transaction_rollback - if transaction_open + if transaction_open && !outside_transaction? transaction_open = false decrement_open_transactions if open_transactions == 0 @@ -131,7 +145,9 @@ module ActiveRecord raise unless database_transaction_rollback.is_a? ActiveRecord::Rollback end ensure - if transaction_open + if outside_transaction? + @open_transactions = 0 + elsif transaction_open decrement_open_transactions begin if open_transactions == 0 diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 828f321767..c4ef2be82e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -532,6 +532,16 @@ module ActiveRecord def rollback_db_transaction execute "ROLLBACK" end + + if PGconn.public_method_defined?(:transaction_status) + # ruby-pg defines Ruby constants for transaction status, + # ruby-postgres does not. + PQTRANS_IDLE = defined?(PGconn::PQTRANS_IDLE) ? PGconn::PQTRANS_IDLE : 0 + + def outside_transaction? + @connection.transaction_status == PQTRANS_IDLE + end + end def create_savepoint execute("SAVEPOINT #{current_savepoint_name}") -- cgit v1.2.3