嗨,我最近正在处理 ruby-odbc。
根据我的逻辑,ruby-odbc 引发了一个异常,Active Record 库应该捕获它。但此异常消息的编码是 ASCII-8BIT,这将引发另一个编码不兼容的异常。我暂时不想修改 Active Record 或使用tiny_tds(暂时)。
所以我想知道是否有一种方法可以将异常消息的编码更改为给定的编码?
我尝试在传递给 rb_raise 之前转换错误消息,但没有成功。结果仍然是 ASCII-8BIT。 那么我是否在做一些愚蠢的事情,因为 ruby c 扩展中的任何字符串都是 ASCII-8BIT 或者我在转换过程中犯了错误? 有什么想法吗?
==================附加整个背景================ 我在cloudvolumes/ruby-odbc的基础上修改并重新编译了odbc.c文件,主要是这个函数:
static VALUE stmt_prep_int(int argc, VALUE *argv, VALUE self, int mode)
对于如下所示的所有句子:
rb_raise(Cerror, "%s",msg);
我替换为:
rb_odbc_raise_error(Cerror, msg);
这个新函数定义为:
static VALUE rb_odbc_raise_error(VALUE err,char * msg){
VALUE e;
VALUE vmsg = rb_str_new2(msg);
#ifdef USE_RB_ENC
rb_enc_associate_index(vmsg,rb_enc );
msg = rb_string_value_cstr(&vmsg);
#endif
e = rb_exc_new2(err,msg);
rb_exc_raise(e);
return Qnil;
}
注意,USE_RB_ENC 和 rb_enc (utf8) 的定义来自 repo: https://github.com/cloudvolumes/ruby-odbc .
将引发异常的 ruby 脚本如下所示:
begin
cfg = ActiveRecord::Base.connection_config
if cfg && cfg[:adapter] == "sqlserver"
ActiveRecord::Base.connection_pool.with_connection do |connection|
domain_name = ENV['USERDOMAIN']
computer_name = "#{ENV['COMPUTERNAME']}中文$"
name = "#{domain_name}\\#{computer_name}"
puts "Granting database access to #{name.encode(Encoding.locale_charmap)}"
connection.execute("CREATE LOGIN [#{name}] FROM WINDOWS")
end
else
puts "Database is not configured or is not SQL Server"
end
rescue Interrupt
raise
rescue Exception => e
#do something.
end
此脚本应引发异常
"42000 (15401) [Microsoft][ODBC SQL Server Driver][SQL Server]Windows NT user or group 'ZHUO\APPMANAGERDEV中文$' not found. Check the name again.".
但是,当下面的activerecord-3.2.21/lib/active_record/connection_adapters/abstract_adater.rb捕获异常时,由于rails设置为utf-8并且e.message的编码为ASCII-8BIT,将会出现异常:
" Exception Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and UTF-8".
因此根本看不到原始的错误消息。
def log(sql, name = "SQL", binds = [])
@instrumenter.instrument(
"sql.active_record",
:sql => sql,
:name => name,
:connection_id => object_id,
:binds => binds) { yield }
rescue Exception => e
message = "#{e.class.name}: #{e.message}: #{sql}"
@logger.debug message if @logger
exception = translate_exception(e, message)
exception.set_backtrace e.backtrace
raise exception
end
最佳答案
您可以使用rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
。
关于Ruby C 扩展异常消息编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33911762/