Ruby C 扩展异常消息编码

标签 ruby exception encoding odbc

嗨,我最近正在处理 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/

相关文章:

ruby - 输出顺序

python 从 if 语句和 try-except 调用自定义异常

ruby - 在 Ruby 中评估的最后一个表达式

ruby-on-rails - RVM 查找系统 gems 的可执行文件

ruby - ruby 中的 TOPLEVEL_BINDING 是什么?

c++ - 如何将异常报告给 boost::future?

c# - 将 "large"数据流设置为 BitmapImage 的源时出错

vim - 在 Vim 中将编码和文件编码设置为 utf-8

java - 将带有整数的 ArrayList 转换为 UTF-16 字符串

python - python 中的 iso-8859-1 和 utf8