diff --git a/contrib/ruby/ext/trilogy-ruby/cext.c b/contrib/ruby/ext/trilogy-ruby/cext.c index 7e128e1a..5244a306 100644 --- a/contrib/ruby/ext/trilogy-ruby/cext.c +++ b/contrib/ruby/ext/trilogy-ruby/cext.c @@ -18,7 +18,7 @@ VALUE Trilogy_CastError; static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError, Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError, - Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result; + Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_EOFError; static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout, id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count, @@ -96,7 +96,7 @@ static void trilogy_syserr_fail_str(int e, VALUE msg) rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg); } else if (e == EPIPE) { // Backwards compatibility: This error class makes no sense, but matches legacy behavior - rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", msg); + rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION: EPIPE", msg); } else { VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg); rb_exc_raise(exc); @@ -158,6 +158,10 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE ": TRILOGY_DNS_ERROR", rbmsg); } + case TRILOGY_CLOSED_CONNECTION: { + rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", rbmsg); + } + default: rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": %s", rbmsg, trilogy_error(rc)); } @@ -1176,6 +1180,9 @@ RUBY_FUNC_EXPORTED void Init_cext() Trilogy_CastError = rb_const_get(Trilogy, rb_intern("CastError")); rb_global_variable(&Trilogy_CastError); + Trilogy_EOFError = rb_const_get(Trilogy, rb_intern("EOFError")); + rb_global_variable(&Trilogy_EOFError); + id_socket = rb_intern("socket"); id_host = rb_intern("host"); id_port = rb_intern("port"); diff --git a/contrib/ruby/lib/trilogy/error.rb b/contrib/ruby/lib/trilogy/error.rb index 72569f9e..e4af3a47 100644 --- a/contrib/ruby/lib/trilogy/error.rb +++ b/contrib/ruby/lib/trilogy/error.rb @@ -20,7 +20,7 @@ class SyscallError .select { |c| c.is_a?(Class) && c < SystemCallError } .each do |c| errno_name = c.to_s.split('::').last - ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::Error }) + ERRORS[c::Errno] = const_set(errno_name, Class.new(c) { include Trilogy::ConnectionError }) end ERRORS.freeze @@ -112,7 +112,13 @@ class SSLError < BaseError include ConnectionError end + # Raised on attempt to use connection which was explicitly closed by the user class ConnectionClosed < IOError include ConnectionError end + + # Occurrs when a socket read or write returns EOF or when an operation is + # attempted on a socket which previously encountered an error. + class EOFError < BaseConnectionError + end end diff --git a/contrib/ruby/test/test_helper.rb b/contrib/ruby/test/test_helper.rb index f532fd75..e8983b94 100644 --- a/contrib/ruby/test/test_helper.rb +++ b/contrib/ruby/test/test_helper.rb @@ -144,7 +144,7 @@ def create_test_table(client) def assert_raises_connection_error(&block) err = assert_raises(Trilogy::Error, &block) - if err.is_a?(Trilogy::QueryError) + if err.is_a?(Trilogy::EOFError) assert_includes err.message, "TRILOGY_CLOSED_CONNECTION" elsif err.is_a?(Trilogy::SSLError) assert_includes err.message, "unexpected eof while reading"