💩

mysqlダンプ→インポート→文字化け→くそおおおおおおお! ~ ブチ切れエンジニアのボヤキ

2024/06/28に公開

はじめに

オッス!オラ、エンジニア!!
今回はmysqlのデータベースをダンプとインポートで移してみっぞ!!
これはオラが実際にハマった経験面白おかしくその原因と対策を書いたものだ。
これがみんなの役に立ったらならオラすんげぇ嬉しいぞ!!

ちなみにOSはWindowsだからよろしくな!
powershellのバージョンは5.1だ!
自分のバージョンが気になる奴は$PSVersionTableってやると調べられるぞ!

始めっぞ!!!

まず、データベースを用意したぞ!

クエリってやつらしいぞ!
CREATE database dragonball;
CREATE TABLE chara (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `Quote` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO chara (name, Quote) VALUES 
("悟空", "クリリンのことかーーーーーっ!!!!!"),
("ウーロン", "ギャルのパンティーおくれーーーっ!!!!!"),
("フリーザ", "わたしの戦闘力は530000です。"),
("ベジータ", "へっ! きたねえ花火だ"),
("少年悟空", "それ食えんのか?"),
("フリーザ", "初めてですよ・・・ここまで私をコケにしたおバカさん達は・・・"),
("野沢雅子", "うっせぇ!ぶっ殺すぞぉ!"),
("アイデンティティ", "口悪ぃなおい!"),
("パラガス", "パッパ、パラガス♪"),
("ブロリー", "親父ぃ・・・"),
("パラガス", "ゑゑゑゑゑゑゑ!?"),
("シュワルツネグァア", "I'll be back");

データベースをダンプすっぞ!!

このコマンドってやつやればダンプ出来るらしいぞ!!

コマンド
mysqldump --default-character-set=utf8mb4 -u root -B dragonball > dragonball.dmp

オラもう訳わかんねぇぞ!
自慢じゃねえが、オラ面倒くせえ事が大嫌いなもんだからよぉ
ローカルホストだしrootだしパスワードは勿論いらねぇっていう環境だ!

オラと同じような人はさっきのコマンドでOKだ!
だけど、違う人は色々オプションが必要だからそこはググってなんとかしてけれよ!!

じゃあ、このコマンドどうやって実行するかなんだけどよ。
Windowsでは次の2つでできるらしいぞ!

  • cmd(コマンドプロンプト)
  • powershell

オラ、強え奴見るとワクワクすっからよぉ!
powershellでやってみっぞ!

コマンド
PS C:\Users\gokuu> mysqldump --default-character-set=utf8mb4 -u root dragonball > dragonball.dmp
mysqldump : 用語 'mysqldump' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識
されません。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行
してください。
発生場所 行:1 文字:1
+ mysqldump --default-character-set=utf8mb4 -u root dragonball > dragon ...
+ ~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (mysqldump:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

うおおおおおおおお!!!!

はぁはぁ・・・手強え奴だったが、何とか倒したぞ!
これでオラもダンプってやつが出来たぞ!

ダンプをインポートすっぞ!!

よっしゃ、やっぞ!!
さっきやったダンプファイルをインポートすればいいらしいぞ!
さっきはパスで手こずったから今回はダンプファイルをインポートする所に置いておくぞ!!
ちなみにオラはC:\xampp_8_2_12\mysql\binここにあるデータベースにインポートしていくぞ!

インポートするときはこのコマンドをやればいいらしいぞ!

コマンド
# オラ、パスとかよくわかんねぇから先に移動すっぞ!
cd "C:\xampp_8_2_12\mysql\bin"

# インポートすっぞ!
.\mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp

よっしゃ、早速やっぞ!!

powershellでやっぞ!!
PS C:\Users\gokuu> cd "C:\xampp_8_2_12\mysql\bin"
PS C:\xampp_8_2_12\mysql\bin> .\mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp
発生場所 行:1 文字:15
+ .\mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp
+               ~
演算子 '<' は、今後の使用のために予約されています。
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RedirectionNotSupported

あああああああああああ!!!

オラ、すっげぇイライラしてきたぞ!!!

Powershellって全然パワーねぇじゃねえか!!
仕方ねぇからここは cmd(コマンドプロンプト) でもう一回やっぞ!!

注)powershellそのものは cmd(コマンドプロンプト)より遥かにパワフル ですが複雑多岐な要件を実装しているためかこのような問題が度々起こり得ます。

コマンドプロンプトでやっぞ!!
C:\Users\gokuu>cd "C:\xampp_8_2_12\mysql\bin"

C:\xampp_8_2_12\mysql\bin>mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp
ERROR: ASCII '\0' appeared in the statement, but this is not allowed unless option --binary-mode is enabled and mysql is run in non-interactive mode. Set --binary-mode to 1 if ASCII '\0' is expected. Query: '-'.

コマンドプロンプトでも、できねぇじゃねぇかよ!!!!!

くそおおおおおおお!

できねぇぞ!!?(原因考察)

できねぇぞ!!?

どうしてだよおおおおおおお!!!

なぜこのような事が起こったのか

まずダンプはpowershellで以下のコマンドを行いました。

powershellのコマンド
# 実行可能なパスに移動してからやったよ!
mysqldump --default-character-set=utf8mb4 -u root dragonball > dragonball.dmp

次に、powershellでは出来なかったのでコマンドプロンプトで以下のコマンドを行いました。

コマンドプロンプトのコマンド
mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp

原因はエンコーディング(文字コード)と>(リダイレクト)の挙動の差にある!

エンコーディング(文字コード)

有名なものでは以下のものがあります。

  • ASCII
  • SHIFT-JIS
  • UTF-8
  • EUC-JP

これは人間が理解できるあいうえおという文字列をPCが理解できる227 129 130 227 129 132 227 129 134 227 129 136 227 129 138と言ったバイト数値に相互変換します。(UTF-8の場合)

ちなみにSHIFT-JISの場合130 160 130 162 130 164 130 166 130 168 です。
全然違いますね・・・。

そしてファイルはPCが理解できるバイト数値で文字列を保持しています。
つまりUTF-8あいうえおと書いて保存したファイルは内部的に227 129 130 227 129 132 227 129 134 227 129 136 227 129 138と言った数値で保存されています。

なので・・・227 129 130 227 129 132 227 129 134 227 129 136 227 129 138と保存されたファイルをSHIFT-JISで開くと縺ゅ>縺�縺医♀と表示されます。

これが文字化けという現象です。

>(リダイレクト)の差

さて、文字化けの仕組みは分かりました。
ということはエンコーディング(文字コード)を合わせれば文字化けしないということでもあります。
だけれども、今回は文字化けしています。

次に、>(リダイレクト)の差に着目してみましょう。
リダイレクトとは出力の向き先を変更するための機能です。
powershellとコマンドプロンプトの挙動を見比べてみましょう。

コマンド
mysqldump --default-character-set=utf8mb4 -u root -B dragonball > dragonball.dmp

今回はこのコマンドをpowershellでやってみました。
ではコマンドプロンプトでやってみるとどうでしょうか?

コマンドプロンプトでやっぞ!!
rem ダンプすっぞ!!
mysqldump --default-character-set=utf8mb4 -u root -B dragonball > dragonball.dmp

rem インポートすっぞ!!
mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp

実行結果

不思議ですね・・・、コマンドプロンプトでやった場合は上手くいきました。

なぜ同じコマンドを実行したのに結果に差が出たのでしょうか?
ここを少し深掘りしていってみましょう。

色々調べてみた

  • powershell
    > について

    バイナリファイルのリダイレクトについて

  • cmd(コマンドプロンプト)

    コマンドプロンプトの入出力ストリームのリダイレクトについて

    リダイレクトという概念について

    バイトストリームという概念について

考察及び調査の結果概要

  • powershell
    >一般的なリダイレクト演算子よりもOut-Fileというコマンドレットに近い挙動をしており、バイトではなく文字列のストリームにより処理されOut-Fileの規定エンコーディングでUTF16LEに変換されたため文字化けを起こした。

  • コマンドプロンプト
    調査と挙動からの推測だが、コマンドプロンプトの>一般的なリダイレクト演算子でありバイトストリームにより処理されるため文字化けが発生しなかった。

対策

cmd(コマンドプロンプト)でやりましょう。

結局のところこれが一番簡単だと思います。

コマンドプロンプトでやっぞ!!
rem ダンプすっぞ!!
mysqldump --default-character-set=utf8mb4 -u root -B dragonball > dragonball.dmp

rem インポートすっぞ!!
mysql --default-character-set=utf8mb4 -P 3307 -u root < dragonball.dmp

powershellをアップデートしよう!

2024年現在はバージョン7だそうです。
以下の手順を参考にアップデートするもの良さそうです。
https://learn.microsoft.com/ja-jp/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.4

さいごに

今回は淡々と手順説明しがちな技術記事に面白さを加えてみる試みで書いてみました。
できねぇぞ!!?(原因考察)までは、スラスラ執筆できましたが、原因考察編になるととても今回のテーマは奥がとても深いのと信頼できる情報源が中々見つからずに4日程かかりました。

こんな調子で書きたい記事はまだあるので心が折れてなければ再チャレンジしようと思います。

Discussion