Бекапы это хорошо, а еще лучше когда они работают так как надо когда они нужны. На одном из проектов понадобилось восстановить дамп из 745 триггеров и накатить их на рабочую MySQL базу.
MySQL позволяет использовать любые имена триггеров, в том числе с использованием точек (например:
analitica.cron.indeg.y.run.a_insert
). А mysqldump при создании дампа не учитывает это обстоятельство и добавляет конструкцию для их дропа следующего вида:/*!50032 DROP TRIGGER IF EXISTS analitica.cron.indeg.y.run.a_insert */;
Подвох ожидает при попытке эти дампы накатить на базу где эти триггеры уже созданы. С точки зрения MySQL этот запрос не дропнет триггер, потому что не найдет триггер с таким именем. Для корректной работы имя триггера должно быть заключено в апострофы.
В попытках найти обходное решение зарепортил соответствующий репорт в баг трекер Перконы, а они уже продублировали аналогичный репорт в официальный трекер MySQL.
Поскольку исправлять этот баг будут долго, а дампы мне нужны прямой сейчас. Решить эту задачу я решил самым прямолинейным способом, а именно самостоятельно пропатчив mysqldump. Для этого склонировал официальный репозиторий перконовского дитрибутива MySQL 5.6 с GitHub'а.
git clone --recursive --depth 1 https://github.com/percona/percona-server/
Открыл файл
client/mysqldump.c
и добавил апострофы к конструкции DROP TRIGGER IF EXISTS
в паре мест. Если посмотреть diff, то получается такой патч:@@ -3517,7 +3517,7 @@ static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs,
fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n");
if (opt_drop_trigger)
- fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", (*show_trigger_row)[0]);
+ fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS `%s` */;\n", (*show_trigger_row)[0]);
fprintf(sql_file,
"DELIMITER ;;\n"
@@ -3604,7 +3604,7 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
switch_sql_mode(sql_file, ";", row[1]);
if (opt_drop_trigger)
- fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", row[0]);
+ fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS `%s` */;\n", row[0]);
Чтобы собрать пропатченую версию надо поставить пару пакетов и на Ubuntu/Debian, запустить cmake с параметрами из документации к Перконе, а затем make'ом собрать только mysqldump.
apt-get install build-essential cmake bison libaio-dev libncurses5-dev libreadline-dev
cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_CONFIG=mysql_release -DFEATURE_SET=community -DWITH_EMBEDDED_SERVER=OFF
make mysqldump
После компиляции получаем патченую версию mysqldump, в которой имена триггеров экранируются корректно. Можно дампить новым дампером:
./percona-server/client/mysqldump --socket=/var/run/mysqld/mysqld.sock -uroot -p --routines --events --triggers --add-drop-trigger --quote-names --no-create-info --no-data --no-create-db --skip-opt database_name | sed -r 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/' > dump.sql
kloppspb
> пропатчив mysqldump
Ну или что-то в этом роде :)
dotZero
Это слишком просто :)
kloppspb
Зато быстро :)
BTW, ещё мысль тут же промелькнула, ну, чтобы не ждать патча :) Если надо только триггеры, то можно их выцепить через банальное «show triggers», оно кавычит нормально. Вроде бы…
khim
Может и быстро, но неправильно: если в базе встретится вот эта вот статья, то после восстановления из backup'а в ней станет несколько больше апострофов, что не есть карашо.
kloppspb
«или что-то в этом роде» предполагает, что регексп писался на коленке только для демонстрации идеи. Немного раздумий и он правится до правильного состояния.
Впрочем, поклоннкам картинки в комменте ниже, любое движение в этом направлении рекомендовать не буду.
ivlis
xonix
Может это тоже стоит пропатчить…
kingu
Зачем использовать заведомо проблемные имена?
dotZero
Их писал человек пришедший из Postgre там это не было проблемой.