diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb index fc94cf9e4242aadd7289e679189c4e0f0ac8b99b..4688c51a9f999c64b40d4a0c7bd49372fcead40e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb @@ -74,37 +74,19 @@ def exec_delete(sql, name = "SQL", binds = []) end alias :exec_update :exec_delete - def begin_isolated_db_transaction(isolation) #:nodoc - raise ArgumentError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted - raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache? - - Thread.current.thread_variable_set("read_uncommitted", @connection.get_first_value("PRAGMA read_uncommitted")) - @connection.read_uncommitted = true - begin_db_transaction - end - def begin_db_transaction #:nodoc: log("begin transaction", "TRANSACTION") { @connection.transaction } end def commit_db_transaction #:nodoc: log("commit transaction", "TRANSACTION") { @connection.commit } - reset_read_uncommitted end def exec_rollback_db_transaction #:nodoc: log("rollback transaction", "TRANSACTION") { @connection.rollback } - reset_read_uncommitted end private - def reset_read_uncommitted - read_uncommitted = Thread.current.thread_variable_get("read_uncommitted") - return unless read_uncommitted - - @connection.read_uncommitted = read_uncommitted - end - def execute_batch(statements, name = nil) sql = combine_multi_statements(statements) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 3ef368e1d67d5e8a93444c51d2a7d0f9648831f7..a87312d95b625410a9add0fc297bbcb4dd3f66b7 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -26,7 +26,7 @@ def sqlite3_connection(config) # Allow database path relative to Rails.root, but only if the database # path is not the special path that tells sqlite to build a database only # in memory. - if ":memory:" != config[:database] && !config[:database].to_s.starts_with?("file:") + if ":memory:" != config[:database] config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root) dirname = File.dirname(config[:database]) Dir.mkdir(dirname) unless File.directory?(dirname) @@ -116,10 +116,6 @@ def supports_savepoints? true end - def supports_transaction_isolation? - true - end - def supports_partial_index? true end @@ -329,10 +325,6 @@ def build_insert_sql(insert) # :nodoc: sql end - def shared_cache? # :nodoc: - @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE) - end - def get_database_version # :nodoc: SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)")) end diff --git a/activerecord/test/cases/adapters/sqlite3/transaction_test.rb b/activerecord/test/cases/adapters/sqlite3/transaction_test.rb deleted file mode 100644 index 5d65312d36282c95f93de00c96677d3d39231bb1..0000000000000000000000000000000000000000 --- a/activerecord/test/cases/adapters/sqlite3/transaction_test.rb +++ /dev/null @@ -1,118 +0,0 @@ -# frozen_string_literal: true - -require "cases/helper" - -class SQLite3TransactionTest < ActiveRecord::SQLite3TestCase - test "shared_cached? is true when cache-mode is enabled" do - with_connection(flags: shared_cache_flags) do |conn| - assert_predicate(conn, :shared_cache?) - end - end - - test "shared_cached? is false when cache-mode is disabled" do - flags =::SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE - - with_connection(flags: flags) do |conn| - assert_not_predicate(conn, :shared_cache?) - end - end - - test "raises when trying to open a transaction in a isolation level other than `read_uncommitted`" do - with_connection do |conn| - assert_raises(ArgumentError) do - conn.transaction(requires_new: true, isolation: :something) do - conn.transaction_manager.materialize_transactions - end - end - end - end - - test "raises when trying to open a read_uncommitted transaction but shared-cache mode is turned off" do - with_connection do |conn| - error = assert_raises(StandardError) do - conn.transaction(requires_new: true, isolation: :read_uncommitted) do - conn.transaction_manager.materialize_transactions - end - end - - assert_match("You need to enable the shared-cache mode", error.message) - end - end - - test "opens a `read_uncommitted` transaction" do - with_connection(flags: shared_cache_flags) do |conn1| - conn1.create_table(:zines) { |t| t.column(:title, :string) } if in_memory_db? - conn1.transaction do - conn1.transaction_manager.materialize_transactions - conn1.execute("INSERT INTO zines (title) VALUES ('foo')") - - with_connection(flags: shared_cache_flags) do |conn2| - conn2.transaction(joinable: false, isolation: :read_uncommitted) do - assert_not_empty(conn2.execute("SELECT * FROM zines WHERE title = 'foo'")) - end - end - - raise ActiveRecord::Rollback - end - end - end - - test "reset the read_uncommitted PRAGMA when transactions is rolled back" do - with_connection(flags: shared_cache_flags) do |conn| - conn.transaction(joinable: false, isolation: :read_uncommitted) do - assert_not(read_uncommitted?(conn)) - conn.transaction_manager.materialize_transactions - assert(read_uncommitted?(conn)) - - raise ActiveRecord::Rollback - end - - assert_not(read_uncommitted?(conn)) - end - end - - test "reset the read_uncommitted PRAGMA when transactions is commited" do - with_connection(flags: shared_cache_flags) do |conn| - conn.transaction(joinable: false, isolation: :read_uncommitted) do - assert_not(read_uncommitted?(conn)) - conn.transaction_manager.materialize_transactions - assert(read_uncommitted?(conn)) - end - - assert_not(read_uncommitted?(conn)) - end - end - - test "set the read_uncommited PRAGMA to its previous value" do - with_connection(flags: shared_cache_flags) do |conn| - conn.transaction(joinable: false, isolation: :read_uncommitted) do - conn.instance_variable_get(:@connection).read_uncommitted = true - assert(read_uncommitted?(conn)) - conn.transaction_manager.materialize_transactions - assert(read_uncommitted?(conn)) - end - - assert(read_uncommitted?(conn)) - end - end - - private - def read_uncommitted?(conn) - conn.instance_variable_get(:@connection).get_first_value("PRAGMA read_uncommitted") != 0 - end - - def shared_cache_flags - ::SQLite3::Constants::Open::READWRITE | SQLite3::Constants::Open::CREATE | ::SQLite3::Constants::Open::SHAREDCACHE | ::SQLite3::Constants::Open::URI - end - - def with_connection(options = {}) - conn_options = options.reverse_merge( - database: in_memory_db? ? "file::memory:" : ActiveRecord::Base.configurations["arunit"][:database] - ) - conn = ActiveRecord::Base.sqlite3_connection(conn_options) - - yield(conn) - ensure - conn.disconnect! if conn - end -end diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index 84fdb544ba31fa4ba51534434203dcea105b2a4c..29329694129b8ca35fe4699b08c57ca35502e61d 100644 --- a/activerecord/test/cases/transaction_isolation_test.rb +++ b/activerecord/test/cases/transaction_isolation_test.rb @@ -2,7 +2,7 @@ require "cases/helper" -unless ActiveRecord::Base.connection.supports_transaction_isolation? && !current_adapter?(:SQLite3Adapter) +unless ActiveRecord::Base.connection.supports_transaction_isolation? class TransactionIsolationUnsupportedTest < ActiveRecord::TestCase self.use_transactional_tests = false @@ -10,8 +10,6 @@ class Tag < ActiveRecord::Base end test "setting the isolation level raises an error" do - skip if current_adapter?(:SQLite3Adapter) - assert_raises(ActiveRecord::TransactionIsolationError) do Tag.transaction(isolation: :serializable) { Tag.connection.materialize_transactions } end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 1d210e3d156b8e8a8d2f41e3dac97844cc09e723..b5c1cac3d9e1eda078393153c268705b972ec357 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -1127,7 +1127,7 @@ def test_no_automatic_savepoint_for_inner_transaction end end if Topic.connection.supports_savepoints? -if ActiveRecord::Base.connection.supports_transaction_isolation? && !in_memory_db? +if ActiveRecord::Base.connection.supports_transaction_isolation? class ConcurrentTransactionTest < TransactionTest # This will cause transactions to overlap and fail unless they are performed on # separate database connections.