MySQLに RENAME DATABASE
が存在していたのは 5.1.7から5.1.22の短い期間だけ(5.1のGAは5.1.30なのでその時にはもう消えていた)
にも拘わらず、かつての日本語版ドキュメントのカバー範囲が「5.1.15-betaまで」なため、俺と似たような時期に日本語ドキュメントを使って勉強していた人はよく知っているイメージ。
ちなみに無くなった理由は「色々考慮してないものが多すぎて色々壊れまくったから」だと思う(個人の見解です)
- MySQL Bugs: #17565: RENAME DATABASE destroys events
- MySQL Bugs: #19392: Rename Database: Crash if case change
- MySQL Bugs: #22182: Renaming database doesn’t work
- MySQL Bugs: #28360: RENAME DATABASE destroys routines
とはいえごく稀に、「現在のデータベースを他の名前にリネームして切り戻し用にとっておきたい(データだけでも)」ということはあるので、 RENAME DATABASE
を模した動きをするスクリプトを作った。
その名も yt-rename-database
Yoku-san no ToolKIT の仲間なので、CentOS 7.xなら releaseごとにrpm を作ってある。
(ただし 0.2.1-0 にはバグがあって yt-rename-database --help
ができない…(゚∀。)
$ /usr/local/bin/yt-rename-database --help
..
* --ask-pass, --ask-password, --askpass
Ask --password by prompt
* --debug
Set debug output
* --dest=value, --destination=value, --dst=value, --to=value
Database-name moving to
* --execute
Execute statements. If --execute is not specified, only print statements.
* --force, -f
Force RENAME if --to has TRIGGERS, EVENTS, ROUTINES, VIEWS, and Foreign Keys.
* --from=value, --source=value, --src=value
Database-name moving from
* --help, --usage
Show this message
* --host=value, -h=value { Default: localhost }
MySQL host
* --ignore-event, --ignore-events
Force RENAME if --to has EVENTS.
* --ignore-fk
Force RENAME if --to has ROUTINES.
* --ignore-routine, --ignore-routines
Force RENAME if --to has ROUTINES.
* --ignore-trigger, --ignore-triggers
Force RENAME if --to has TRIGGERS.
* --ignore-view, --ignore-views
Force RENAME if --to has VIEWS.
* --password=value, -p=value
Password for the user specified by --user
* --port=value, -P=value
MySQL port number
* --quiet, --silent, -q, -s
No output any messages
* --socket=value, -S=value
Path to mysql.sock
(this parameter is used when --host=localhost)
* --timeout=value { Default: 1 }
Seconds before timeout
(Set into read_timeout, write_timeout, connect_timeout)
* --user=value, -u=value
MySQL account using for connection and checking
(need REPLICATION CLIENT, PROCESSLIST and global SELECT priv)
* --verbose, -v
Verbose output mode
* --version, -V
Show ytkit version
..
接続関連のオプションは mysql
コマンドラインクライアントのものとほぼ一緒。
地味に ytkit
で一番気に入ってるのはオプションパーサーで、MySQL公式のクライアント群を模して --socket=/tmp/mysql.sock
, --socket /tmp/mysql.sock
, -S /tmp/mysql.sock
, -S/tmp/mysql.sock
が全部ちゃんとパースできる(おまけに公式ではできない -S=/tmp/mysql.sock
もできる)
-p
の引数が空っぽの時のハンドルは模すのが面倒だったので percona-toolkit や innotopみたいに --askpass
オプションがついている(これ、ptとinnotopで確か —ask-passと—askpassと揺れててたまに間違えるので両方とも受け取れるようにしてる)
--from
と --to
が必須オプションになっていて、そいつらを指定しているとこんな風にペロッと「 RENAME TABLE
で中身を全部新しいスキーマに移す」ようなSQLスクリプトを吐く。
$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --to=d11 --from=d1
Password:
-- Emulating RENAME DATABASE d1 TO d11
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
CREATE DATABASE `d11`;
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
RENAME TABLE `d1`.`t1` TO `d11`.`t1`;
-- I'm dry-run mode. Specify --execute if you wish to execute statements by script.
DROP DATABASE `d1`;
もとの RENAME DATABASE
時代にひどい目に遭ったらしいForeignKeyやTrigger, Viewなどがあるとそのままではエラーになる。
$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --from=admintool --to=_admintool
Password:
-- Emulating RENAME DATABASE admintool TO _admintool
admintool has Foreign Keys, not supporting.(For *forcing-execution*, use --ignore-fk or --force) at /home/yoku0825/git/ytkit/bin/../lib/Ytkit/RenameDatabase.pm line 99.
警告を無視する(その辺の不整合はセルフでカバーする)場合のオプションはエラー出力に含まれるようになっている(さっきコミットしたばっか)。
$ /usr/local/bin/yt-rename-database -uroot -S /usr/mysql/8.0.20/data/mysql.sock --askpass --from=admintool --to=_admintool --ignore-fk --execute
-- Emulating RENAME DATABASE admintool TO _admintool
-- admintool has Foreign Keys, not supporting.(For *forcing-execution*, use --ignore-fk or --force) at /home/yoku0825/git/ytkit/bin/../lib/Ytkit/RenameDatabase.pm line 93.
--execute
をつけると実際にスクリプトを実行してリネームする。
あんまり使うこと考えてなくて、 --execute
なしでSQLスクリプトとして出力させてぺたこんと貼ればいいんじゃないかなと思っている。
基本的に SHOW TABLES
と RENAME TABLE
を使っているだけなので、ワンライナーでも余裕でいけると思う。
$ mysql -uroot -sse "SHOW TABLES FROM <from_db>" | while read table ; do
> mysql -uroot -ve "RENAME TABLE <from_db>.$table TO <to_db>.$table"
> done
ふと思ったので作ってみたのでした。