ruby-1.9とsqlite3メモ

rubyを1.9にバージョンアップしたらw3mで使っていた
ローカルCGIが動かなくなったのでメモ。
原因は文字列の文字コードの扱いが変わったことだった。

リテラル

まずはリテラルの例

exp.rb

#!/usr/bin/env ruby
str="文字列リテラル"
$ ruby exp.rb
exp.rb:2: invalid multibyte char (US-ASCII)
exp.rb:2: invalid multibyte char (US-ASCII)

怒られる

encodingを指定する。

#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-
str="文字列リテラル"
p str
p str.encoding
$ ruby exp.rb
"文字列リテラル"
#<Encoding:UTF-8>

OK

外部からの文字列

外部としてsqlite3から文字列を入力する場合。

# UTF-8で文字列を格納
$ cat tmp.sql
DROP TABLE IF EXISTS words;

CREATE TABLE words (
  id INTEGER PRIMARY KEY
    , word VARCHAR UNIQUE
    );

INSERT INTO words (
  word
  )
SELECT "睦月"
UNION ALL SELECT "如月"
UNION ALL SELECT "弥生"
;

# DB作成
$ sqlite3 tmp.db < tmp.sql

exp.rb

#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

require 'sqlite3'

if ARGV.length<1 then
  exit
end

db=SQLite3::Database.new(ARGV[0])

db.execute("SELECT word FROM words") do |row|
  p row
  p row.map{|col| col.encoding}
  p row.map{|col| col.force_encoding 'utf-8'}
end

実行

$ ruby exp.rb tmp.db
["\xE7\x9D\xA6\xE6\x9C\x88"]
[#<Encoding:ASCII-8BIT>]
["睦月"]
["\xE5\xA6\x82\xE6\x9C\x88"]
[#<Encoding:ASCII-8BIT>]
["如月"]
["\xE5\xBC\xA5\xE7\x94\x9F"]
[#<Encoding:ASCII-8BIT>]
["弥生"]

リテラルでは無いので
# -*- encoding: utf-8 -*-
は効かない。
外部からの文字列はASCII-8BITになるので
encoding_forceforce_encodingでエンコード情報を与えてやるということらしい。
File.openやCGI経由での入力なんかも気をつける必要がある様子。
確かsqliteutf-8を使う約束になっていたのでutf-8決めうちで
いいかもしれない。

外部エンコーディングの決めうち

Encoding.default_external='utf-8'

とする。
sqlite3には影響しなかった。