sakaikの日々雑感~日常編

sakaikの日々の雑記。食べ物、読み物、お出かけ(旅行)などなど

トリガのダンプ結果を流すとレプリケーションが停止する件

 MySQL5.0の新しい機能のひとつであるトリガー。便利な機能であることは疑う余地はないのですが、その他の新機能と同様、どうもイマヒトツ感を感じます。

 今回見つけたのは、mysqldumpでダンプしたトリガ生成文を実行するとレプリケーションが停止してしまう、というもの。レプリケーション環境で運用している場合はかなり致命的です。 

 原因は、bin-logに書かれる内容にあります。

 以下詳細ご覧ください。


(1)テーブルとトリガの作成

 以下のようにテーブル test_table1 と トリガ tri_test を作成します。

CREATE DATABASE test2;
use test2;

CREATE TABLE test_table1 (no int, str varchar(16));

DELIMITER //
CREATE TRIGGER tri_test BEFORE INSERT ON test_table1 FOR EACH ROW begin
  declare v_no integer;
    select no into v_no from test_table1 for update;
    update test_table2 set cnt = cnt + 1;
    set new.no = v_no;
end//
DELIMITER ;


(2)このテーブル定義とトリガをダンプします

コマンド:

mysqldump -uroot test2

ダンプ結果:

(前略)
--
-- Table structure for table `test_table1`
--

DROP TABLE IF EXISTS `test_table1`;
CREATE TABLE `test_table1` (
  `no` int(11) default NULL,
  `str` varchar(16) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Dumping data for table `test_table1`
--


/*!40000 ALTER TABLE `test_table1` DISABLE KEYS */;
LOCK TABLES `test_table1` WRITE;
UNLOCK TABLES;
/*!40000 ALTER TABLE `test_table1` ENABLE KEYS */;

/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;
DELIMITER ;;
/*!50003 SET SESSION SQL_MODE="" */;;
/*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER 
`tri_test` BEFORE INSERT ON `test_table1` FOR EACH ROW begin
  declare v_no integer;
    select no into v_no from test_table1 for update;
    update test_table2 set cnt = cnt + 1;
    set new.no = v_no;
end */;;

DELIMITER ;
(後略)

(3)テーブルを削除後、ダンプ結果を流し込み

・まず DROP TABLE test_table1; でテーブルを削除。

・その後 先ほどのダンプ結果を流し込み。


その結果 bin-log には・・・・

# at 982
#060422  0:02:53 server id 1  end_log_pos 1096  Query   thread_id=4     exec_tim
e=0     error_code=0
SET TIMESTAMP=1145631773;
/*!40000 ALTER TABLE `test_table1` DISABLE KEYS */;
# at 1096
#060422  0:02:53 server id 1  end_log_pos 1209  Query   thread_id=4     exec_tim
e=0     error_code=0
SET TIMESTAMP=1145631773;
/*!40000 ALTER TABLE `test_table1` ENABLE KEYS */;
# at 1209
#060422  0:02:54 server id 1  end_log_pos 1524  Query   thread_id=4     exec_tim
e=0     error_code=0
SET TIMESTAMP=1145631774;
SET @@session.sql_mode=0;
CREATE DEFINER=`root`@`localhost` TRIGGER `tri_test` BEFORE INSERT ON 
                                          `test_table1` FOR EACH ROW begin
  declare v_no integer;
    select no into v_no from test_table1 for update;
    update test_table2 set cnt = cnt + 1;
    set new.no = v_no;
end */;
# End of log file

 なんと CREATE TRIGGER 文の end の後に */ がついています! 開始の /*! がないのに!!

 これによりレプリケーションのスレーブでの実行がエラーとなり、めでたくレプリケーション停止の結果を得られることになりましたとさ。

 

 log-bin に記録する際に、先頭に /*!50002 とかがつくのが正しいのか、 それとも */ は除去するほうが良いのかはわかりませんが、

 いずれにせよコメント(バージョン指定)処理が、bin-log出力処理の中で半端な状態であることは確かです。



 なお、view でも同様の現象が起きます。

# at 2350
#060422  0:17:28 server id 1  end_log_pos 2564  Query   thread_id=6     exec_tim
e=0     error_code=0
SET TIMESTAMP=1145632648;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW
`test_view` AS select `test_table1`.`no` AS `no` from `test_table1` */;
# End of log file




20520