diff options
author | Doug Barth <doug@pagerduty.com> | 2013-11-05 10:04:00 -0800 |
---|---|---|
committer | Doug Barth <doug@pagerduty.com> | 2013-11-05 11:47:08 -0800 |
commit | 5d870c929157b7c7949c9356d4f88b97c8848ec3 (patch) | |
tree | b9daf6484495a9c24fdd60fbe695068fb045d296 /activerecord/test/cases | |
parent | 44406d1e77061ce22effaae4698918c1f9f6271a (diff) | |
download | rails-5d870c929157b7c7949c9356d4f88b97c8848ec3.tar.gz rails-5d870c929157b7c7949c9356d4f88b97c8848ec3.tar.bz2 rails-5d870c929157b7c7949c9356d4f88b97c8848ec3.zip |
Don't swallow exceptions in transctional statements
The MySQL connection adapater swallows all StandardError exceptions,
which includes Mysql::Error and Mysql2::Error. The comment in the
exception clause claims errors thrown here indicate that transactions
aren't supported by the server but that isn't necessarily true. It's
possible the MySQL server has gone away and swallowing a failed commit
may let the application return a successful response when the data has
not been saved. Also, replication libraries like Galera require that the
application handle exceptions thrown at BEGIN/COMMIT.
I'm unable to determine what version of MySQL threw an exception for
transactional statements. I tried as far back as 3.23.49 with InnoDB
disabled but BEGIN & COMMIT statements do not throw an error. If there's
a real case for this logic to continue, we could instead push this
behavior into a configuration setting.
The exception swallowing has been there since the beginning:
db045dbbf60b53dbe013ef25554fd013baf88134
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r-- | activerecord/test/cases/adapters/mysql/connection_test.rb | 26 | ||||
-rw-r--r-- | activerecord/test/cases/adapters/mysql2/connection_test.rb | 26 |
2 files changed, 52 insertions, 0 deletions
diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 1844a2e0dc..ece0ee77fb 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -40,6 +40,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase @connection.update('set @@wait_timeout=1') sleep 2 assert !@connection.active? + + # Repair all fixture connections so other tests won't break. + @fixture_connections.each do |c| + c.verify! + end end def test_successful_reconnection_after_timeout_with_manual_reconnect @@ -159,6 +164,27 @@ class MysqlConnectionTest < ActiveRecord::TestCase end end + def test_mysql_begin_db_transaction_can_throw_an_exception + @connection.expects(:exec_query).with('BEGIN').raises('OH NOES') + assert_raise RuntimeError do + @connection.begin_db_transaction + end + end + + def test_mysql_commit_db_transaction_can_throw_an_exception + @connection.expects(:execute).with('COMMIT').raises('OH NOES') + assert_raise RuntimeError do + @connection.commit_db_transaction + end + end + + def test_mysql_rollback_db_transaction_can_throw_an_exception + @connection.expects(:execute).with('ROLLBACK').raises('OH NOES') + assert_raise RuntimeError do + @connection.rollback_db_transaction + end + end + private def run_without_connection diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index 679c515e8c..943ca9d552 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -18,6 +18,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase @connection.update('set @@wait_timeout=1') sleep 2 assert !@connection.active? + + # Repair all fixture connections so other tests won't break. + @fixture_connections.each do |c| + c.verify! + end end def test_successful_reconnection_after_timeout_with_manual_reconnect @@ -84,6 +89,27 @@ class MysqlConnectionTest < ActiveRecord::TestCase @connection.execute "DROP TABLE `bar_baz`" end + def test_mysql_begin_db_transaction_can_throw_an_exception + @connection.expects(:execute).with('BEGIN').raises('OH NOES') + assert_raise RuntimeError do + @connection.begin_db_transaction + end + end + + def test_mysql_commit_db_transaction_can_throw_an_exception + @connection.expects(:execute).with('COMMIT').raises('OH NOES') + assert_raise RuntimeError do + @connection.commit_db_transaction + end + end + + def test_mysql_rollback_db_transaction_can_throw_an_exception + @connection.expects(:execute).with('ROLLBACK').raises('OH NOES') + assert_raise RuntimeError do + @connection.rollback_db_transaction + end + end + private def run_without_connection |