From c99c572d370dc3b4fc6e0f324f80126fdc2db3f9 Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Wed, 14 Aug 2019 11:51:04 +0100 Subject: [PATCH] Improve detection of ActiveRecord::StatementTimeout with mysql2 adapter in the edge case when the query is terminated by MySQL server during filesort. See https://bugs.mysql.com/bug.php?id=96537 for more details. --- activerecord/CHANGELOG.md | 4 ++++ .../connection_adapters/abstract_mysql_adapter.rb | 3 ++- .../cases/adapters/mysql2/mysql2_adapter_test.rb | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 95fa78aa0f33e..c73fe9fdb5dbe 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Improve detection of ActiveRecord::StatementTimeout with mysql2 adapter in the edge case when the query is terminated during filesort. + + *Kir Shatrov* + * Stop trying to read yaml file fixtures when loading Active Record fixtures. *Gannon McGibbon* diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 0fe16270edc80..3f9ba5ae02ce5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -574,6 +574,7 @@ def extract_precision(sql_type) # See https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html ER_DB_CREATE_EXISTS = 1007 + ER_FILSORT_ABORT = 1028 ER_DUP_ENTRY = 1062 ER_NOT_NULL_VIOLATION = 1048 ER_NO_REFERENCED_ROW = 1216 @@ -617,7 +618,7 @@ def translate_exception(exception, message:, sql:, binds:) Deadlocked.new(message, sql: sql, binds: binds) when ER_LOCK_WAIT_TIMEOUT LockWaitTimeout.new(message, sql: sql, binds: binds) - when ER_QUERY_TIMEOUT + when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT StatementTimeout.new(message, sql: sql, binds: binds) when ER_QUERY_INTERRUPTED QueryCanceled.new(message, sql: sql, binds: binds) diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index cfc182377347b..189d5e0bb9dc6 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -240,6 +240,21 @@ def test_read_timeout_exception ActiveRecord::Base.establish_connection :arunit end + def test_statement_timeout_error_codes + raw_conn = @conn.raw_connection + assert_raises(ActiveRecord::StatementTimeout) do + raw_conn.stub(:query, ->(_sql) { raise Mysql2::Error.new("fail", 50700, ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::ER_FILSORT_ABORT) }) { + @conn.execute("SELECT 1") + } + end + + assert_raises(ActiveRecord::StatementTimeout) do + raw_conn.stub(:query, ->(_sql) { raise Mysql2::Error.new("fail", 50700, ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::ER_QUERY_TIMEOUT) }) { + @conn.execute("SELECT 1") + } + end + end + private def with_example_table(definition = "id int auto_increment primary key, number int, data varchar(255)", &block) super(@conn, "ex", definition, &block)