LINUX.ORG.RU

yoyo migrations не может развернуть БД на mysql

 ,


0

1

Столкнулся с тем, что yoyo migrations не может развернуть БД на mysql, в которой объявляются процедуры с REPEAT.

Допустим, мы хотим использовать чуть подчищенный вариат дампа произведенного с помощью mysqldump:

DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

DELIMITER ;;
CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
	return test_var;
end ;;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
end ;;
DELIMITER ;

Как видим, mysql его спокойно разворачивает:

[popov-aa@archlinux yoyo]$ mysql -u root -p -h 172.28.1.21 test_db < ./migrations/20200717_01_dHiTT-create-schema.sql 
Enter password: 
[popov-aa@archlinux yoyo]$ 

Теперь попробуем развернуть этот же дамп с помощью yoyo, получаем ошибку:

DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
	return test_var;
end ;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
	repeat
		set test_var = test_var + 1;
	until test_var < 10 end repeat;
end ;
Получаем:
[popov-aa@archlinux yoyo]$ yoyo apply
/home/popov-aa/.local/lib/python3.8/site-packages/pymysql/cursors.py:170: Warning: (1051, "Unknown table 'test_db.test_table'")
  result = self._query(query)
Traceback (most recent call last):
...
pymysql.err.ProgrammingError: (1064, "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 'DELIMITER' at line 1")
[popov-aa@archlinux yoyo]$ 
Модифицируем дамп, удалив DELIMITER:
[popov-aa@archlinux yoyo]$ yoyo apply
Traceback (most recent call last):
...
pymysql.err.ProgrammingError: (1064, "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 '' at line 8")
[popov-aa@archlinux yoyo]$ 
При этом вариант без REPEAT проходит на ура:
DROP TABLE IF EXISTS `test_table`;
CREATE TABLE `test_table` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

DROP TABLE IF EXISTS `yoyo_lock`;
CREATE TABLE `yoyo_lock` (
  `locked` int NOT NULL DEFAULT '1',
  `ctime` timestamp NULL DEFAULT NULL,
  `pid` int NOT NULL,
  PRIMARY KEY (`locked`)
) ENGINE=InnoDB;

CREATE DEFINER=`root`@`%` FUNCTION `test_function`() RETURNS int
    READS SQL DATA
    DETERMINISTIC
begin
	declare test_var int default 1;
	return test_var;
end ;

CREATE DEFINER=`root`@`%` PROCEDURE `test_procedure`()
begin
	declare test_var int default 1;
end ;
[popov-aa@archlinux yoyo]$ yoyo apply
[popov-aa@archlinux yoyo]$ 
У кого-нибудь есть догадки в чем проблема и как быть?

Ответ на: комментарий от Kazun3500

Сомнительно. Я посмотрел исходники. Утилита не берет на себя грех парсить sql, а прочитав файл целиком отдает его библиотеке sqlparse. Та уже возвращает операторы, который по очереди исполняются утилитой. Эта библиотека неправильно парсит исходный SQL. Попробую запилить багрепорт.

popov-aa ()
Ответ на: комментарий от popov-aa

средство для версионирования и миграций БД.

mysqldump + git. Юзал, мне зашло. Главное делать одну строчку на insert и не делать truncate одних и тех же данных. Но сейчас я бы не стал так делать, потому что для дампа надо базу останавливать по-доброму, бекап надо накопительный в real-time, а раз в день с дельтой - это херня полная. Что у тебя за база?

crutch_master ★★★★★ ()
Ответ на: комментарий от crutch_master

Оно вообще не об этом. Рекомендую ознакомиться с yoyo-migrations, крайне удобная и полезная вещь.

Все изменения в БД описываются миграциями, состоящими из шагов, операторов DDL. Так же в качестве шага можно написать обработчик на пайтоне, если миграция сложная и необходимо произвести сложные манипуляции с данными. В базе данных пишутся выполненные миграции, так что всегда можно понять какой версии схема. Актуализация любой схемы производится в автоматическом режиме одной командой.

Все здорово, но sqlparse некорректно парсит дамп MySQL.

popov-aa ()
Ответ на: комментарий от popov-aa

Запостил багрепорт в sqlparse, а пока перешел на flyway. Оказывается он выполнен не только в веде java-api и плагина maven, но еще и предлагает command line interface, который по возможностям полностью соответствует yoyo-migrations.

popov-aa ()