MySQLの最近のブログ記事

最近 MySQL では UTF-8 しか扱ってなかったのだが、今回作成したプログラムは「Shift_JIS で書かれた CSV ファイルを読み込んで DB に登録。もちろん NEC 特殊文字や NEC 選定 IBM 拡張文字もガンガン混ざってますぜ!」という香ばしいもの。

ソース自体は EUC-JP で書いたので、DB の中身も EUC-JP で保管するようにして、自前のコード変換関数で Shift_JIS→EUC-JP に変換している。
CREATE TABLE するときにも、ちゃんと DEFAULT CHARSET=ujis 付けてるしね。

なのに、データを登録した後で phpMyAdmin でチェックすると、日本語化け化けやん。

どうも、MySQL ではサーバ側で勝手に文字コードのエンコードをしてしまうので、UTF-8 以外のコードではこういう文字化けが発生してしまうという。
日頃 PostgreSQL ばかり使ってて、いきなり MySQL に来たら絶対ハマっちゃうよなあ、これは。

で、解決方法としては、本来の SQL を投げる前に、

SET NAMES ujis

という SQL を発行すること。

具体的には、

$query    =<<EndOfQuery;
SET NAMES ujis
EndOfQuery

$sth = $dbh->prepare($query);
$sth->execute();

としてから、本来の SQL を

$query    =<<EndOfQuery;
INSERT
INTO
  hogehoge
~本来の SQL~
EndOfQuery

$sth = $dbh->prepare($query);
$sth->execute();

と実行すれば良いと。

なんだかなぁ(^^; テーブル作る時に DEFAULT CHARSET=ujis なんて宣言している意味がなかったな。(^^;
まあ、DB に詳しい偉い人たちが文句を言ってないってことは、この実装も間違いではないんだろうけど、なんだかなあ(^^;

ちなみに、MySQL の設定ファイルや実行時のオプションであれこれする方法もあるようなのだが、今回使用しているのが安いレンタルサーバで、MySQL の設定ファイルは触れない仕様らしいので、毎度 SET NAMES ujis を発行する方法しかないようだ。

とほほ。またも無駄な時間を・・・
bakebake.jpgいや、まあ、MySQL に限ったことじゃないけどな。

PostgreSQL にしても、バックアップしてリストアしたデータが化けちゃうってのは良くあることで、まあ、最初の原型作ったヤツらにとっては英語が全てなわけで、その後多言語化のために色々な仕組みが継ぎ足されたわけだから、問題が起こって当たり前って感じもしますが。
日本語だけでも、何個のコード体系があるんだよ、実際。(^^;

今回の MovableType の移行でもハマったぁ!

mysqldump によるバックアップ時と、mysql によるリストア時の、default-character-set の指定だけで何とかならんかいなと色々やったんだけど、結局、

mysqldump --default-character-set=binary -u hoge -phoge mtos > mtos_20091106.dump

で、文字コード変えずにバックアップして、mtos_20091106.dump を一旦ローカル PC にダウンロード。
で、秀丸エディタを使って中身を修正。

修正箇所は、

DROP TABLE IF EXISTS `mt_ts_job`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `mt_ts_job` (
  `ts_job_jobid` int(11) NOT NULL AUTO_INCREMENT,
<略>
  KEY `mt_ts_job_funccoal` (`ts_job_funcid`,`ts_job_coalesce`),
  KEY `mt_ts_job_funcrun` (`ts_job_funcid`,`ts_job_run_after`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;

この、「ENGINE=MyISAM DEFAULT CHARSET=latin1;」の部分。
ここが、latin1 になってるので、utf8 に修正する(テーブルの数だけ。40箇所くらいかな)。
「ENGINE=MyISAM DEFAULT CHARSET=utf8;」という具合に。

で、これを新サーバにアップして、

mysql --default-character-set=utf8 -u hogehoge -p mtos < mtos_20091106.dump

とリストアする。

この方法以外ではどうすることも出来なかった。

ああ・・・面倒臭い、面倒臭い。元の MySQL の設定にも依存しちゃうし、なかなかすっきりいかないもんですなあ。
次に遭遇した問題が、mt.cgi の実行で、

Connection error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

というエラーが発生しちゃう件。

いや、確かに、旧サーバでは Socket ファイルを /var/lib/mysql 以下に作成していたけど、新サーバでは /tmp の下に作成してる。だから、'/var/lib/mysql/mysql.sock' を使ってソケット通信しようとすれば、そりゃあエラーになるよ。

・・・が、決め打ちなの?(^^;

どこかで指定してるのかと思い、grep しまくったけど結局 '/var/lib/mysql/mysql.sock' を固定的にセットしている部分は見つからず。
でも、まあ、どっかに記述があるんだろうな・・・

別に、/tmp 以下にこだわっているわけではないので、ディレクトリを /var/lib/mysql に変えてもいいのだが(/etc/my.cnf の socket = /tmp/mysql.sock の記述を修正するだけだし)、何となく悔しいので MovableType 側で対応することに。

結局、mt-config.cgi に環境変数として path を記述するのが一番スマートな気がしたので、

DBSocket /tmp/mysql.sock

という記述を追加。
これで、件のエラーは発生せず、正常に管理画面を使うことが出来るようになったのである。

・・・が、そんな俺に、新たな敵が。
あ、いや、新たな問題が・・・

mysqladmin で hoge-hoge という名前の DB 作って、そいつを mysql 上で扱おうとしたらエラーが・・・

mysql> GRANT ALL ON hoge-hoge.* TO dbuser@localhost;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-hoge.* TO dbuser@localhost' at line 1

どうも、ハイフンが式として判断されてるのか?コマンドの始まりと判断されているのか?・・・と思い、シングルクォーテーションで囲ってみたけど、

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''hoge-hoge'' at line 1

やっぱり駄目。同じエラーだなあ・・・
\ でエスケープしてみたら?

ERROR:
Unknown command '\-'.
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\-hoge' at line 1

やっぱり駄目。つーか、エラーが増えてるし。(^^;

結局、バッククォーテーションで囲めばよかった。

mysql> GRANT ALL ON `hoge-hoge.*` TO dbuser@localhost;

こんな感じ。
そうかあ。MySQL じゃ、ハイフンを含んだ DB名を使うときは常にバッククォーテーションで囲まないと駄目なのか。ハイフンを含んだ DB名を使うのって今回が初めてなので知らんかった。(^^;

いちいち面倒なので、ハイフン使うのやめて、DBの名前を hoge_hoge に変えちゃった。
これが一番正解。(笑)

OpenPNE の DB を移行するため、旧サーバで

mysqldump -u hoge -phogehoge pne_db > pne_db_backup_20081230

で吸い上げたデータを、新サーバで

mysql -u hoge -phogehoge pne_db < pne_db_backup_20081230

したら、

ERROR at line 415: Unknown command '\'.

とエラーに。
ああ・・・新しいサーバの MySQL の default-character-set は utf8 だった。
つーことで、明示的に、

mysql -u hoge -phogehoge --default-character-set=sjis pne_db < pne_db_backup_20081230

と default-character-set を指定してやればOK。

ああ、そういえば昔、別の仕事で同じようなエラーが出た時は、エラーになった行の \ を、\\ と全部エスケープして登録したな。
今時は、UTF-8 をディフォルトの文字コードに指定していることが多いだろう。
Shift_JIS で作ってる DB を移行するときは、--default-character-set=sjis を忘れるなということだな。

ずっと Oracle ばかり使ってると、「あり?ROWNUM って MySQL で、どうすんだっけ?」となっちゃうので(すまんのお、最近記憶力がなくて)メモっとく。

20件目から10件表示なら、

SELECT
    *
FROM
    hogehoge
LIMIT
    20, 10

でね。LIMIT を使いましょう。

最後の 10件を、降順に ORDER BY せずに抜くために、

SELECT
    *
FROM
    c_access_log
LIMIT
    (
        SELECT 
            COUNT(*) - 10
        FROM 
            c_access_log
    ), 10

とかやってみたけど、You have an error in your SQL syntax と怒られちゃって駄目。LIMIT のところにサブクエリの値は突っ込めないのか?

MySQL で、並び順を変えずにラスト10件を取得するスマートな方法ってどうすんだろう?

<参考>
MySQLとApacheのもやもや情報
http://pagerank.cocolog-nifty.com/blog/2007/12/mysqloraclerown_4c4f.html

このアーカイブについて

このページには、過去に書かれたブログ記事のうちMySQLカテゴリに属しているものが含まれています。

次のカテゴリはPostgreSQLです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら