Skip to content

Commit aece179

Browse files
committed
Raise specialized exception for connection and timeout errors
1 parent 4e6369b commit aece179

5 files changed

Lines changed: 49 additions & 14 deletions

File tree

ext/mysql2/client.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "mysql_enc_name_to_ruby.h"
1616

1717
VALUE cMysql2Client;
18-
extern VALUE mMysql2, cMysql2Error;
18+
extern VALUE mMysql2, cMysql2Error, cMysql2TimeoutError;
1919
static VALUE sym_id, sym_version, sym_header_version, sym_async, sym_symbolize_keys, sym_as, sym_array, sym_stream;
2020
static VALUE sym_no_good_index_used, sym_no_index_used, sym_query_was_slow;
2121
static ID intern_brackets, intern_merge, intern_merge_bang, intern_new_with_args;
@@ -659,7 +659,7 @@ static VALUE do_query(void *args) {
659659
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
660660

661661
if (retval == 0) {
662-
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
662+
rb_raise(cMysql2TimeoutError, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
663663
}
664664

665665
if (retval < 0) {

ext/mysql2/mysql2_ext.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#include <mysql2_ext.h>
22

3-
VALUE mMysql2, cMysql2Error;
3+
VALUE mMysql2, cMysql2Error, cMysql2TimeoutError;
44

55
/* Ruby Extension initializer */
66
void Init_mysql2() {
77
mMysql2 = rb_define_module("Mysql2");
88
cMysql2Error = rb_const_get(mMysql2, rb_intern("Error"));
9+
cMysql2TimeoutError = rb_const_get(cMysql2Error, rb_intern("TimeoutError"));
910

1011
init_mysql2_client();
1112
init_mysql2_result();

ext/mysql2/statement.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <mysql2_ext.h>
22

33
VALUE cMysql2Statement;
4-
extern VALUE mMysql2, cMysql2Error, cBigDecimal, cDateTime, cDate;
4+
extern VALUE mMysql2, cMysql2Error, cMysql2TimeoutError, cBigDecimal, cDateTime, cDate;
55
static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s;
66
static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year;
77

lib/mysql2/error.rb

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,47 @@ class Error < StandardError
88
replace: '?'.freeze,
99
}.freeze
1010

11-
BaseConnectionError = Class.new(Error)
11+
ConnectionError = Class.new(Error)
12+
TimeoutError = Class.new(Error)
1213

1314
CODES = {
14-
1045 => AccessDenied = Class.new(BaseConnectionError),
15-
2005 => UnknownHost = Class.new(BaseConnectionError),
15+
1205 => TimeoutError, # ER_LOCK_WAIT_TIMEOUT
1616
}
1717

18+
[
19+
1044, # ER_DBACCESS_DENIED_ERROR
20+
1045, # ER_ACCESS_DENIED_ERROR
21+
1152, # ER_ABORTING_CONNECTION
22+
1153, # ER_NET_PACKET_TOO_LARGE
23+
1154, # ER_NET_READ_ERROR_FROM_PIPE
24+
1155, # ER_NET_FCNTL_ERROR
25+
1156, # ER_NET_PACKETS_OUT_OF_ORDER
26+
1157, # ER_NET_UNCOMPRESS_ERROR
27+
1158, # ER_NET_READ_ERROR
28+
1159, # ER_NET_READ_INTERRUPTED
29+
1160, # ER_NET_ERROR_ON_WRITE
30+
1161, # ER_NET_WRITE_INTERRUPTED
31+
32+
2001, # CR_SOCKET_CREATE_ERROR
33+
2002, # CR_CONNECTION_ERROR
34+
2003, # CR_CONN_HOST_ERROR
35+
2004, # CR_IPSOCK_ERROR
36+
2005, # CR_UNKNOWN_HOST
37+
2006, # CR_SERVER_GONE_ERROR
38+
2007, # CR_VERSION_ERROR
39+
2009, # CR_WRONG_HOST_INFO
40+
2012, # CR_SERVER_HANDSHAKE_ERR
41+
2013, # CR_SERVER_LOST
42+
2020, # CR_NET_PACKET_TOO_LARGE
43+
2026, # CR_SSL_CONNECTION_ERROR
44+
2027, # CR_MALFORMED_PACKET
45+
2047, # CR_CONN_UNKNOW_PROTOCOL
46+
2048, # CR_INVALID_CONN_HANDLE
47+
2049, # CR_UNUSED_1
48+
].each { |c| CODES[c] = ConnectionError }
49+
50+
CODES.freeze
51+
1852
attr_reader :error_number, :sql_state
1953

2054
# Mysql gem compatibility
@@ -24,7 +58,7 @@ class Error < StandardError
2458
def initialize(msg, server_version = nil, error_number = nil, sql_state = nil)
2559
@server_version = server_version
2660
@error_number = error_number
27-
@sql_state = sql_state.encode(ENCODE_OPTS)
61+
@sql_state = sql_state ? sql_state.encode(ENCODE_OPTS) : nil
2862

2963
super(clean_message(msg))
3064
end

spec/mysql2/client_spec.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
end
2020
end
2121

22-
it "should raise a Mysql::Error::UnknownHost upon connection failure" do
23-
expect do
22+
it "should raise a Mysql::Error::ConnectionError upon connection failure" do
23+
expect {
2424
# The odd local host IP address forces the mysql client library to
2525
# use a TCP socket rather than a domain socket.
2626
new_client('host' => '127.0.0.2', 'port' => 999999)
27-
end.to raise_error(Mysql2::Error::UnknownHost)
27+
}.to raise_error(Mysql2::Error::ConnectionError)
2828
end
2929

3030
it "should raise an exception on create for invalid encodings" do
@@ -561,7 +561,7 @@ def run_gc
561561
client = new_client(read_timeout: 0)
562562
expect do
563563
client.query('SELECT SLEEP(0.1)')
564-
end.to raise_error(Mysql2::Error)
564+
end.to raise_error(Mysql2::Error::TimeoutError)
565565
end
566566

567567
# XXX this test is not deterministic (because Unix signal handling is not)
@@ -924,10 +924,10 @@ def run_gc
924924
end
925925
end
926926

927-
it "should raise a Mysql2::Error::AccessDenied exception upon connection failure due to invalid credentials" do
927+
it "should raise a Mysql2::Error::ConnectionError exception upon connection failure due to invalid credentials" do
928928
expect {
929929
new_client(:host => "localhost", :username => 'asdfasdf8d2h', :password => 'asdfasdfw42')
930-
}.to raise_error(Mysql2::Error::AccessDenied)
930+
}.to raise_error(Mysql2::Error::ConnectionError)
931931

932932
expect do
933933
new_client(DatabaseCredentials['root'])

0 commit comments

Comments
 (0)