diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 8214e9393b0..65ffc7281c2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -277,6 +277,7 @@ module ActiveRecord type_casted_binds: -> { type_casted_binds(binds) }, name: name, connection: self, + transaction: current_transaction, cached: true } end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 1f87acac7ec..9b0d4fe4f56 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -1118,6 +1118,7 @@ module ActiveRecord statement_name: statement_name, async: async, connection: self, + transaction: current_transaction, row_count: 0, &block ) diff --git a/activerecord/test/cases/instrumentation_test.rb b/activerecord/test/cases/instrumentation_test.rb index ae354b07ecd..77ad38e2c34 100644 --- a/activerecord/test/cases/instrumentation_test.rb +++ b/activerecord/test/cases/instrumentation_test.rb @@ -170,5 +170,36 @@ module ActiveRecord ensure ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber end + + def test_payload_with_implicit_transaction + expected_transaction = Book.current_transaction + + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event| + if event.payload[:name] == "Book Count" + assert_same expected_transaction, event.payload[:transaction] + end + end + + Book.count + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) + end + + def test_payload_with_explicit_transaction + expected_transaction = nil + + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event| + if event.payload[:name] == "Book Load" + assert_same expected_transaction, event.payload[:transaction] + end + end + + Book.transaction do |transaction| + expected_transaction = transaction + Book.first + end + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) + end end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index ee35b67f6ce..4abb0321e2c 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -1067,4 +1067,40 @@ class QueryCacheExpiryTest < ActiveRecord::TestCase assert_equal @connection_1, @connection_2 end + + test "payload with implicit transaction" do + expected_transaction = Task.current_transaction + + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event| + if event.payload[:cached] + assert_same expected_transaction, event.payload[:transaction] + end + end + + Task.cache do + 2.times { Task.count } + end + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) + end + + test "payload with explicit transaction" do + expected_transaction = nil + + subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event| + if event.payload[:cached] + assert_same expected_transaction, event.payload[:transaction] + end + end + + Task.transaction do |transaction| + expected_transaction = transaction + + Task.cache do + 2.times { Task.count } + end + end + ensure + ActiveSupport::Notifications.unsubscribe(subscriber) + end end diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index e4642ffa70b..6a8a362eaf6 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -360,6 +360,7 @@ The `:cache_hits` key is only included if the collection is rendered with `cache | `:sql` | SQL statement | | `:name` | Name of the operation | | `:connection` | Connection object | +| `:transaction` | Current transaction | | `:binds` | Bind parameters | | `:type_casted_binds` | Typecasted bind parameters | | `:statement_name` | SQL Statement name | @@ -374,6 +375,7 @@ Adapters may add their own data as well. sql: "SELECT \"posts\".* FROM \"posts\" ", name: "Post Load", connection: , + transaction: binds: [], type_casted_binds: [11], statement_name: nil, @@ -381,6 +383,10 @@ Adapters may add their own data as well. } ``` +If there is no transaction started at the moment, `:transaction` has a null +object with UUID `00000000-0000-0000-0000-000000000000` (the nil UUID). This may +happen, for example, issuing a `SELECT` not wrapped in a transaction. + #### `strict_loading_violation.active_record` This event is only emitted when [`config.active_record.action_on_strict_loading_violation`][] is set to `:log`.