よくあるmysqldumpの文字コード問題とか

もともと、2006年ごろに話題になった話で、いまさらすぎるんですけどメモ。
(要するに、使う文字コードを明示的に指定しとけばいいんですけど、デフォルトのまんまなら要らんことしないで欲しかったという愚痴)

さて、この状態で

$ mysqldump  データベース名 > ダンプファイル

とかを実行すると、ダンプファイルの中身が化けてしまう。
それを回避するには、オプションとして-–default-character-set=binary という指定をすれば、変換はしなくなるようです。

$ mysqldump --default-character-set=binary データベース名 > ダンプファイル

(追記)リカバリーの方法

参考記事:The page is not found
DBの文字コード:latin1、登録されたデータの文字コード:euc-jpをmysqldumpでutf8で出力してしまった場合(file1.txtとする)の対処(復元したEUC-JPのファイルをfile2.txtとする)コード。
註:このコードでは、入力はutf8で、出力がlatin1になることは分かると思うが、実は、スクリプトの内部ではutf8で処理が行われている(use utf8の指定のため)。たまたま今回はfile1.txtの文字コードはutf8だが、それ以外の場合は、文字コードの変換が起きる。(これがPerlでよくあるdouble encodingという後述の問題の原因らしい)

#!/bin/env perl
use utf8;
use Encode;
open READ, '<:encoding(utf8)', 'file1.txt';
open WRITE, '>:encoding(latin1)', 'file2.txt';
while(my $data = <READ>){ 
  print WRITE $data;
}
close WRITE;
close READ;
exit; 

上記のコードでは、ファイル名がプログラムに埋め込まれているので、コマンドとして使いづらいので、標準入力、標準出力を使うと下記のようなコードになる

#!/bin/env perl
use utf8;
use Encode;

binmode STDIN, ':encoding(utf8)';
binmode STDOUT, ':encoding(latin1)';
while(<>) {
  print $_;
}

(追記)dumpしたファイル内のDEFAULT CHARSETの定義によって出力を切り替えるコード

実用にするなら、DEFAULT CHARSETのパターンはもっと精密にしなくてはダメだし、文字コードの変換テーブルも充実させる必要がある。

#/bin/env perl
use utf8;
use Encode;

binmode STDIN, ':encoding(utf8)';
binmode STDOUT, ':bytes';
$outputcharset = 'utf8';

%table = ('latin1', 'latin1', 'sjis', 'shiftjis', 'ujis', 'euc-jp', 'utf8', 'utf8');

while(<>) {
  $line = $_;
  print encode($outputcharset, $line);
  if ($line =~ /^\) ENGINE=[^ ]+ DEFAULT CHARSET=(\w*)[ ;]/) {
    $outputcharset = $table{$1};
  }
}

どんな文字コードがサポートされているかは以下参照。

MySQL文字コードの関係は、深い(汗

もっとも、MySQL文字コードの変換については、データベースの文字コード、mysqldの運用文字コード、サーバOS(system)の文字コードにくわえて、SQLのクライアントの文字コードの間で自動変換してくれるようなので、油断がなりません(汗
現在も、関連の記事を読み中です。

Postgresqlは、とりあえずas isベースのdumpのようです

自分はPostgresqlpg_dumpコマンドでは、内容が化けてしまったという経験はありません。
Postgresqlの場合、どちらかというとデータベースの文字コードをどうやって指定するか、ということがマニュアルのデータベースの作成の項目にはストレートに書いてありません→。実際には、文字セットサポートのところに記述があります。

EUC-JPの文字コードのデータベースを作成する場合は、データベースに次のようなqueryを発行します。

CREATE DATABASE データベース名 WITH ENCODING 'EUC_JP';

もしくは

CREATE DATABASE データベース名 ENCODING = 'EUC_JP';

コマンドラインでは次の様になります。

createdb -E EUC_KR データベース名