$KCODE = 'u'でrailsを動かすとSQLServerへのクエリがエラーを起こすんだが。 前にメーリングリストでも見かけたことがあったような。で、$KCODE = 's'で我慢しるってことだったような。
ちょっと試してみた。
どうも、ADODBをラップしてるWin32OLEのRuby StringとBSTRの変換が問題なような感触。
require 'dbi'
require 'iconv'
$KCODE = 's'
value = 'てすと'
sql = "INSERT INTO hoge(val) VALUES('#{value}')"
usql = "INSERT INTO hoge(val) VALUES('#{Iconv.conv('UTF-8', 'CP932', value)}')"
DBI.connect(connect_string).execute(sql) # => ok
DBI.connect(connect_string).execute(usql) # => データが化ける
$KCODE = 'u'
DBI.connect(connect_string).execute(sql)
# =>
DBI::DatabaseError: Execute
OLE error code:80040E14 in Microsoft OLE DB Provider for SQL Server
文字列 ')' の前で引用符が閉じていません。
HRESULT error code:0x80020009
例外が発生しました。
from /usr/lib/ruby/1.8/DBD/ADO/ADO.rb:135:in `execute'
from /usr/lib/ruby/site_ruby/1.8/dbi.rb:888:in `execute'
from /usr/lib/ruby/site_ruby/1.8/dbi.rb:480:in `execute'
from (irb):66
from :0
DBI.connect(connect_string).execute(usql) # => データが化ける
ということは、ADO.rbで使えるようなADODB.Connectionのラッパを拡張ライブラリで書いてやればいけるのか。 まぁ、そんなことしなくても、セッションに紐付いたコードページを変更してそれに合わせてサーバー側で変換させられれば良いんだけど。でも、その辺の設定がどうしてもわからない。"SET LANGUAGE = "は違うよな。
つーか、Rubyは文字列のエンコーディング周りは遅れてる。Stringが文字列といいつつ実際のところバイト列であるのが痛い。文字列オブジェクトを名乗るからには自分のエンコーディングは知っててほしいよね。エンコーディング情報が文字列オブジェクトじゃなくて$KCODEにあるせいで、エンコーディング混在が難しいわけだ。
Perl5はよーでけとるよなぁ。Encode.pmもあるし羨ましい。
Rubyも2.0ではその辺はなんとかなる予定らしいけれど、2.0リリースより先にm17nがマージされたりしないのかな。そういえばm17nはどうなってたろ。久しぶりに覗いてみよう。なんかお手伝いできそうなことがあれば...
上でああいうコメント書いたけど、既にWin32OLEは対応済みでした。
$KCODE = 'u' の場合には、Win32OLEの利用前に
WIN32OLE.codepage = WIN32OLE::CP_UTF8
を実行すると、BSTR変換時に、RubyのStringをUTF-8として扱います。
artonさん、ありがとうございます。
会社に行かないとSQL Server環境がないのですが、年明けに試してみます。
WIN32OLE.codepage = WIN32OLE::CP_UTF8でうまくいきました。artonさんありがとうございます。
require 'dbi'
require 'iconv'
$KCODE = 's'
value = 'てすと'
usql = "INSERT INTO hoge(val) VALUES('#{Iconv.conv('UTF-8', 'CP932', value)}')"
$KCODE = 'u'
WIN32OLE.codepage = WIN32OLE::CP_UTF8
DBI.connect(connect_string).execute(usql) # ok
よくわからない理由により、コメントが即座には反映されないかもしれませんか゛、ボタンを押して元の画面に戻ってきたならたぶん正しく送信されています。
あー、確かにWin32OLE一族(ASR含む)は、Rubyの文字列とBSTRの相互変換についてはシステムのデフォルトロケールに従って$KCODEは無視してますね(ASRにいたっては勝手に$KCODE='s'を設定してしまうし)。
その動作が問題になるとは思ってなかったけど今となってはちょっとまずかったみたいですね(ruby-listで提案すると助田さんが何か考えてくれるかも。おそらく互換性問題は起きないはずなので)