文字コードがSJISの環境で運用されてるOracleのデータを、PostgreSQLに移行するということをやった時の話。
移行対象データにはシステム独自に登録されている外字や機種依存文字が含まれていた。
当初は、移行元でSJISのcsvファイルを出力し、PostgreSQL側でそのファイルをCOPYコマンドなんかでインポートすれば万事OKだと思っていた。
ところがまず、PostgresのCOPYコマンドでencoding 'sjis'
って指定した場合、外字データがインポートエラーになった。
# psql -d dbname -U postgres -c "COPY TEST_TABLE FROM '/tmp/test_sjis.csv' with encoding 'sjis' csv" ERROR: 符号化方式"SJIS"における0xf1 0xd1バイトシーケンスを持つ文字列は"UTF8"符号化方式では等しくありません (15217) CONTEXT: TEST_TABLEのCOPY。行番号 6 (14503)
機種依存文字はいけたのに、外字はNG。
と言うことは、PostgreSQLで言うところのSJIS
は、純粋なShift-JIS
でもなければ、Windows-31j
でもないPostgreSQL独自解釈の中途半端なSJIS
ということだ。コノヤロウ。
じゃあPostgreSQLでのWindows-31j相当を指定すれば良いかーって思ったら、PostgreSQLのCOPYコマンドではWindows-31j相当のエンコーディング方式指定できねーの。存在してねーの。
# psql -d dbname -U postgres -c "COPY TEST_TABLE FROM '/tmp/test_sjis.csv' with encoding 'Windows-31j' csv" ERROR: オプション "encoding" の引数は有効なエンコーディング名でなければなりません (12302)
この外字どうすんだよ・・・って少しだけ途方にくれたよね。
しょうがないので、SJISのファイルをiconv
コマンドで一旦UTF8に変換してからPostgreSQLにUTF8でインポートする事にした。
だがしかし、ここでも文字コード変換エラーが出た。
iconv -f SJIS -t UTF8
で変換しようとしたら、外字も変換NG、機種依存文字も変換NGだった。
# iconv -f sjis -t utf8 test_sjis.csv iconv: 位置 74 に不正な入力シーケンスがあります
なるほど、iconv
コマンドではSJIS
とは外字も機種依存文字も含まない、真の意味のShift-JIS
だったか。
初めて知ったよ。オーケーオーケー。
てかもしかしたら今まで作ってきたシェルでそう書いて来たかもしれないわ…やっべーw
結論として、iconv -f WINDOWS-31J -t UTF8
で外字も機種依存文字も変換できた。
あとは、普通にPostgreSQLのpsqlでCOPYコマンド使ってあっさりインポート完了。
なんつーか、システムやアプリ、その他でSJIS
っていう文字コードの扱いや意味合いが違いすぎて嫌になるねもう。
機種依存文字や外字がデータに含まれてるならSJIS
じゃなくて、ちゃんとCP932
とかWindows-31j
でエンコードされてるって言おうぜー?