diff --git a/CHANGELOG.md b/CHANGELOG.md index e81c9982..5ce0ddcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Fixed - Fix msec values for time columns. #61 +### Changed + - All SystemCallErrors classified as `Trilogy::Error`. + ## 2.3.0 ### Added diff --git a/contrib/ruby/ext/trilogy-ruby/cext.c b/contrib/ruby/ext/trilogy-ruby/cext.c index 1498d1e6..5925f992 100644 --- a/contrib/ruby/ext/trilogy-ruby/cext.c +++ b/contrib/ruby/ext/trilogy-ruby/cext.c @@ -20,14 +20,14 @@ VALUE Trilogy_CastError; static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError, Trilogy_ConnectionClosedError, Trilogy_ConnectionRefusedError, Trilogy_ConnectionResetError, - Trilogy_TimeoutError, Trilogy_Result; + Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result; 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, id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password, id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key, id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result, - id_from_code, id_connection_options; + id_from_code, id_from_errno, id_connection_options; struct trilogy_ctx { trilogy_conn_t conn; @@ -90,8 +90,8 @@ static void trilogy_syserr_fail_str(int e, VALUE msg) } else if (e == ECONNRESET) { rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg); } else { - // TODO: All syserr should be wrapped. - rb_syserr_fail_str(e, msg); + VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg); + rb_exc_raise(exc); } } @@ -1088,6 +1088,9 @@ RUBY_FUNC_EXPORTED void Init_cext() Trilogy_Result = rb_const_get(Trilogy, rb_intern("Result")); rb_global_variable(&Trilogy_Result); + Trilogy_SyscallError = rb_const_get(Trilogy, rb_intern("SyscallError")); + rb_global_variable(&Trilogy_SyscallError); + Trilogy_CastError = rb_const_get(Trilogy, rb_intern("CastError")); rb_global_variable(&Trilogy_CastError); @@ -1119,6 +1122,7 @@ RUBY_FUNC_EXPORTED void Init_cext() id_multi_statement = rb_intern("multi_statement"); id_multi_result = rb_intern("multi_result"); id_from_code = rb_intern("from_code"); + id_from_errno = rb_intern("from_errno"); id_ivar_affected_rows = rb_intern("@affected_rows"); id_ivar_fields = rb_intern("@fields"); id_ivar_last_insert_id = rb_intern("@last_insert_id"); diff --git a/contrib/ruby/lib/trilogy.rb b/contrib/ruby/lib/trilogy.rb index b3dda50b..2842bd21 100644 --- a/contrib/ruby/lib/trilogy.rb +++ b/contrib/ruby/lib/trilogy.rb @@ -13,6 +13,27 @@ module ConnectionError include Error end + # Trilogy may raise various syscall errors, which we treat as Trilogy::Errors. + class SyscallError + ERRORS = {} + + Errno.constants + .map { |c| Errno.const_get(c) }.uniq + .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 }) + end + + ERRORS.freeze + + class << self + def from_errno(errno, message) + ERRORS[errno].new(message) + end + end + end + class BaseError < StandardError include Error @@ -41,29 +62,14 @@ class CastError < ClientError class TimeoutError < Errno::ETIMEDOUT include ConnectionError - - def initialize(error_message = nil, error_code = nil) - super - @error_code = error_code - end end class ConnectionRefusedError < Errno::ECONNREFUSED include ConnectionError - - def initialize(error_message = nil, error_code = nil) - super - @error_code = error_code - end end class ConnectionResetError < Errno::ECONNRESET include ConnectionError - - def initialize(error_message = nil, error_code = nil) - super - @error_code = error_code - end end # DatabaseError was replaced by ProtocolError, but we'll keep it around as an