俺のメモ帖

とあるインフラ系SEのメモ帖。日常的なものや、趣味や技術的なもとか書けたらいいなぁ。

【Linux】PostgreSQLのCOPYコマンドで、SJIS(Windows-31j)の外字を登録する方法

文字コードSJISの環境で運用されてるOracleのデータを、PostgreSQLに移行するということをやった時の話。

移行対象データにはシステム独自に登録されている外字や機種依存文字が含まれていた。
当初は、移行元でSJIScsvファイルを出力し、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で外字も機種依存文字も変換できた。 あとは、普通にPostgreSQLpsqlでCOPYコマンド使ってあっさりインポート完了。

なんつーか、システムやアプリ、その他でSJISっていう文字コードの扱いや意味合いが違いすぎて嫌になるねもう。
機種依存文字や外字がデータに含まれてるならSJISじゃなくて、ちゃんとCP932とかWindows-31jエンコードされてるって言おうぜー?