List:Commits« Previous MessageNext Message »
From:Dmitry Shulga Date:April 18 2013 9:16am
Subject:bzr push into mysql-trunk branch (Dmitry.Shulga:5412 to 5419) WL#3253
View as plain text  
 5419 Dmitry Shulga	2013-04-18
      wl#3253: Added tests for rpl.

    modified:
      mysql-test/suite/rpl/r/rpl_trigger.result
      mysql-test/suite/rpl/t/rpl_trigger.test
 5418 Dmitry Shulga	2013-04-18
      wl#3253: Added tests for mysqldump. Fixed a bug in output of SHOW CREATE TABLE (the attribute created had wrong value).

    modified:
      mysql-test/r/trigger_wl3253.result
      mysql-test/t/trigger_wl3253.test
      sql/sql_show.cc
 5417 Dmitry Shulga	2013-04-17
      wl#3253: fixed a bug in output of attribute triggers.created.

    modified:
      mysql-test/r/trigger_wl3253.result
      mysql-test/t/trigger_wl3253.test
      sql/sql_show.cc
 5416 Dmitry Shulga	2013-04-17
      wl#3253: Introduced explicit type 'trigger_action_order_type'.

    modified:
      sql/sql_yacc.yy
 5415 Dmitry Shulga	2013-04-17
      wl#3253: Fix possible issue when Trigger::parse_trigger_body() returns true
      as a result of memory allocation failure and Trigger::get_parse_error_message() 
      returns uninitialized error string.

    modified:
      sql/table_trigger_dispatcher.cc
      sql/table_trigger_dispatcher.h
      sql/trigger.h
 5414 Dmitry Shulga	2013-04-16
      wl#3253: Added more comments. Moved some methods in Trigger_chain
      from header to source file. Removed default constructor from Trigger_data.

    modified:
      sql/table_trigger_dispatcher.h
      sql/trigger.cc
      sql/trigger.h
      sql/trigger_chain.cc
      sql/trigger_chain.h
      sql/trigger_loader.cc
 5413 Dmitry Shulga	2013-04-16
      wl#3253: renamed class triggers_chain to trigger_chain.

    renamed:
      sql/triggers_chain.cc => sql/trigger_chain.cc
      sql/triggers_chain.h => sql/trigger_chain.h
    modified:
      sql/CMakeLists.txt
      sql/partition_info.cc
      sql/sp_instr.cc
      sql/sql_show.cc
      sql/table_trigger_dispatcher.cc
      sql/table_trigger_dispatcher.h
      sql/trigger_chain.cc
      sql/trigger_chain.h
 5412 Alexander Nozdrin	2013-04-15 [merge]
      Merge.

    modified:
      sql/table_trigger_dispatcher.cc
=== modified file 'mysql-test/r/trigger_wl3253.result'
--- a/mysql-test/r/trigger_wl3253.result	2013-03-15 15:40:59 +0000
+++ b/mysql-test/r/trigger_wl3253.result	2013-04-18 08:02:16 +0000
@@ -4,10 +4,10 @@
 #
 # Test 1.
 # Check that the sequence of triggers for the same combination 
-# of event type/action type can be created for the table
-# and is fired consequenctly in the order of its creation
+# of event type/action type can be created for a table
+# and is fired consequently in the order of its creation
 # during statement execution.
-# At this test we checks for BEFORE triggers.
+# In this test we check BEFORE triggers.
 # 
 CREATE TABLE t1 (a INT);
 CREATE TABLE t2 (a INT);
@@ -23,10 +23,10 @@ DROP TABLE t1;
 #
 # Test 2.
 # Check that the sequence of triggers for the same combination 
-# of event type/action type can be created for the table
-# and is fired consequenctly in the order of its creation
+# of event type/action type can be created for a table
+# and is fired consequently in the order of its creation
 # during statement execution.
-# At this test we checks for AFTER triggers.
+# In this test we check AFTER triggers.
 # 
 CREATE TABLE t1 (a INT);
 CREATE TABLE t2 (a INT);
@@ -42,7 +42,7 @@ DROP TABLE t1;
 #
 # Test 3.
 # Check that the sequences of triggers for the different event types
-# can be created for the table and are fired consequenctly
+# can be created for a table and are fired consequently
 # in the order of its creation during statement execution.
 #
 CREATE TABLE t1 (a INT);
@@ -77,9 +77,10 @@ SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31
 CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
 SELECT trigger_name, created, action_order FROM information_schema.triggers WHERE trigger_schema='test';
 trigger_name	created	action_order
-tr1_bi	2013-01-31 06:00:00	1
-tr2_bi	2013-01-31 06:00:01	2
+tr1_bi	2013-01-31 09:00:00	1
+tr2_bi	2013-01-31 09:00:01	2
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 #
 # Test 5.
 # Check that action_order attribute isn't shown 
@@ -121,36 +122,39 @@ CREATE TRIGGER tr1_bi BEFORE INSERT ON t
 CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
 SELECT trigger_name, created, action_order FROM information_schema.triggers WHERE trigger_schema='test';
 trigger_name	created	action_order
-tr1_bi	2013-01-31 06:00:01	1
-tr2_bi	2013-01-31 06:00:01	2
+tr1_bi	2013-01-31 09:00:01	1
+tr2_bi	2013-01-31 09:00:01	2
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 #
 # Test 8.
 # Check that SHOW CREATE TRIGGER outputs the CREATED attribute
-# and this one isn't equal to NULL 
+# and it is not NULL
 #
 CREATE TABLE t1 (a INT);
 SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:01');
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
 SHOW CREATE TRIGGER tr1_bi;
 Trigger	sql_mode	SQL Original Statement	character_set_client	collation_connection	Database Collation	created
-tr1_bi	NO_ENGINE_SUBSTITUTION	CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1	latin1	latin1_swedish_ci	latin1_swedish_ci	2013-01-31 06:00:01.00
+tr1_bi	NO_ENGINE_SUBSTITUTION	CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1	latin1	latin1_swedish_ci	latin1_swedish_ci	2013-01-31 09:00:01.00
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 #
 # Test 9.
 # Check that SHOW TRIGGERS outputs the CREATED attribute
-# and this one isn't equal to NULL 
+# and it is not NULL.
 #
 CREATE TABLE t1 (a INT);
 SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:01');
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
 SHOW TRIGGERS;
 Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer	character_set_client	collation_connection	Database Collation
-tr1_bi	INSERT	t1	SET @a:=1	BEFORE	2013-01-31 06:00:01	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr1_bi	INSERT	t1	SET @a:=1	BEFORE	2013-01-31 09:00:01	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 #
 # Test 10.
-# Check that FOLLOWS clause is supported and run correctly.
+# Check that FOLLOWS clause is supported and works correctly.
 #
 CREATE TABLE t1 (a INT);
 CREATE TABLE t2 (a INT);
@@ -172,7 +176,7 @@ DROP TABLE t2;
 DROP TABLE t1;
 #
 # Test 11.
-# Check that PRECEDES clause is supported and run correctly.
+# Check that PRECEDES clause is supported and works correctly.
 #
 CREATE TABLE t1 (a INT);
 CREATE TABLE t2 (a INT);
@@ -194,7 +198,7 @@ DROP TABLE t2;
 DROP TABLE t1;
 #
 # Test 12.
-# Check correct behaviour of PRECEDES clause against FIRST trigger in the chain.
+# Check that the PRECEDES works properly for the 1st trigger in the chain.
 #
 CREATE TABLE t1 (a INT);
 CREATE TABLE t2 (a INT);
@@ -213,7 +217,8 @@ DROP TABLE t2;
 DROP TABLE t1;
 #
 # Test 13.
-# Check that error is reported if the FOLLOWS clause references to non-existing trigger
+# Check that error is reported if the FOLLOWS clause references to
+# non-existing trigger
 #
 CREATE TABLE t1 (a INT);
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
@@ -227,7 +232,8 @@ tr3_bi	2
 DROP TABLE t1;
 #
 # Test 14.
-# Check that error is reported if the PRECEDES clause references to non-existing trigger
+# Check that error is reported if the PRECEDES clause references to
+# non-existing trigger
 #
 CREATE TABLE t1 (a INT);
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
@@ -241,7 +247,8 @@ tr3_bi	2
 DROP TABLE t1;
 #
 # Test 15.
-# Check that action_order value is independent for each type of event (INSERT/UPDATE/DELETE)
+# Check that action_order value is independent for each type of event
+# (INSERT/UPDATE/DELETE)
 #
 CREATE TABLE t1 (a INT);
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
@@ -264,8 +271,8 @@ tr2_bu	2
 DROP TABLE t1;
 #
 # Test 16.
-# Check that the trigger in the clause FOLLOWS/PRECEDES can refences only to the trigger
-# for the same ACTION/TIMINMG
+# Check that the trigger in the clause FOLLOWS/PRECEDES can refences
+# only to the trigger for the same ACTION/TIMINMG
 #
 CREATE TABLE t1 (a INT);
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
@@ -284,5 +291,172 @@ tr1_bi	INSERT	t1	SET @a:=1	BEFORE	#	NO_E
 tr1_bu	UPDATE	t1	SET @a:=3	BEFORE	#	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
 DROP TABLE t1;
 #
+# Test 17. Check that table's triggers are dumped correctly.
+#
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+#
+# Test 18. Check that table's triggers are dumped in right order
+#          taking into account the PRECEDES/FOLLOWS clauses.
+#
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi SET @a:=0;
+CREATE TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=0;
+# Expected order of triggers in the dump is: tr0_bi, tr1_bi, tr1_1_bi, tr2_i.
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi SET @a:=0 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=0 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
+/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = latin1 */ ;
+/*!50003 SET character_set_results = latin1 */ ;
+/*!50003 SET collation_connection  = latin1_swedish_ci */ ;
+/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
+/*!50003 SET sql_mode              = 'NO_ENGINE_SUBSTITUTION' */ ;
+DELIMITER ;;
+/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2 */;;
+DELIMITER ;
+/*!50003 SET sql_mode              = @saved_sql_mode */ ;
+/*!50003 SET character_set_client  = @saved_cs_client */ ;
+/*!50003 SET character_set_results = @saved_cs_results */ ;
+/*!50003 SET collation_connection  = @saved_col_connection */ ;
+#
+# Test 19. Check that table's triggers are dumped correctly in xml.
+#
+CREATE TABLE t1 (a INT);
+SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:00');
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3;
+SET TIMESTAMP=DEFAULT;
+<?xml version="1.0"?>
+<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<database name="test">
+	<table_data name="t1">
+	</table_data>
+	<triggers name="t1">
+		<trigger Trigger="tr1_bi" sql_mode="NO_ENGINE_SUBSTITUTION" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci" created="2013-01-31 09:00:00.00">
+<![CDATA[
+CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1
+]]>
+		</trigger>
+		<trigger Trigger="tr2_bi" sql_mode="NO_ENGINE_SUBSTITUTION" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci" created="2013-01-31 09:00:00.00">
+<![CDATA[
+CREATE DEFINER=`root`@`localhost` TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2
+]]>
+		</trigger>
+		<trigger Trigger="tr1_bu" sql_mode="NO_ENGINE_SUBSTITUTION" character_set_client="latin1" collation_connection="latin1_swedish_ci" Database_Collation="latin1_swedish_ci" created="2013-01-31 09:00:00.00">
+<![CDATA[
+CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3
+]]>
+		</trigger>
+	</triggers>
+</database>
+</mysqldump>
+#
 # End of tests.
 #

=== modified file 'mysql-test/suite/rpl/r/rpl_trigger.result'
--- a/mysql-test/suite/rpl/r/rpl_trigger.result	2013-03-28 10:54:48 +0000
+++ b/mysql-test/suite/rpl/r/rpl_trigger.result	2013-04-18 09:03:55 +0000
@@ -990,4 +990,36 @@ Warning	1196	Some non-transactional chan
 include/diff_tables.inc [master:t1, slave:t1]
 include/diff_tables.inc [master:log, slave:log]
 drop table t1, log;
+#
+# WL#3253: Multiple triggers with the same value TIME/ACTION per table 
+#
+include/rpl_reset.inc
+SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:00');
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi SET @a:=0;
+CREATE TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=11;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @b:=1;
+CREATE TRIGGER tr2_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @b:=2;
+
+---> Synchronizing slave with master...
+---> connection: slave
+SHOW TRIGGERS;
+Trigger	Event	Table	Statement	Timing	Created	sql_mode	Definer	character_set_client	collation_connection	Database Collation
+tr0_bi	INSERT	t1	SET @a:=0	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr1_bi	INSERT	t1	SET @a:=1	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr1_1_bi	INSERT	t1	SET @a:=11	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr2_bi	INSERT	t1	SET @a:=2	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr1_bu	UPDATE	t1	SET @b:=1	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+tr2_bu	UPDATE	t1	SET @b:=2	BEFORE	2013-01-31 09:00:00	NO_ENGINE_SUBSTITUTION	root@localhost	latin1	latin1_swedish_ci	latin1_swedish_ci
+SELECT trigger_name, action_order, created FROM information_schema.triggers WHERE trigger_schema='test';
+trigger_name	action_order	created
+tr0_bi	1	2013-01-31 09:00:00
+tr1_bi	2	2013-01-31 09:00:00
+tr1_1_bi	3	2013-01-31 09:00:00
+tr2_bi	4	2013-01-31 09:00:00
+tr1_bu	1	2013-01-31 09:00:00
+tr2_bu	2	2013-01-31 09:00:00
+DROP TABLE t1;
 include/rpl_end.inc

=== modified file 'mysql-test/suite/rpl/t/rpl_trigger.test'
--- a/mysql-test/suite/rpl/t/rpl_trigger.test	2013-03-28 10:54:48 +0000
+++ b/mysql-test/suite/rpl/t/rpl_trigger.test	2013-04-18 09:03:55 +0000
@@ -539,6 +539,39 @@ connection master;
 drop table t1, log;
 sync_slave_with_master;
 
+--echo #
+--echo # WL#3253: Multiple triggers with the same value TIME/ACTION per table 
+--echo #
+
+connection master;
+--source include/rpl_reset.inc
+
+SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:00');
+CREATE TABLE t1 (a INT);
+
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi SET @a:=0;
+CREATE TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=11;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @b:=1;
+CREATE TRIGGER tr2_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @b:=2;
+--echo
+--echo ---> Synchronizing slave with master...
+
+--sync_slave_with_master
+
+--echo ---> connection: slave
+connection slave;
+
+SHOW TRIGGERS;
+
+SELECT trigger_name, action_order, created FROM information_schema.triggers WHERE trigger_schema='test';
+
+connection master;
+
+DROP TABLE t1;
+--sync_slave_with_master
+
 #
 # End of tests
 #

=== modified file 'mysql-test/t/trigger_wl3253.test'
--- a/mysql-test/t/trigger_wl3253.test	2013-04-15 06:27:31 +0000
+++ b/mysql-test/t/trigger_wl3253.test	2013-04-18 08:02:16 +0000
@@ -89,6 +89,7 @@ CREATE TRIGGER tr2_bi BEFORE INSERT ON t
 SELECT trigger_name, created, action_order FROM information_schema.triggers WHERE trigger_schema='test';
 
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 
 --echo #
 --echo # Test 5.
@@ -113,11 +114,6 @@ DROP TABLE t1;
 --echo # are recreated.
 --echo #
 
-######################################
-# It is MAY BE a BUG. I don't KNOW.  #
-# Think a bit more about it !!!!!!!! #
-######################################
-
 CREATE TABLE t1 (a INT);
 CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
 
@@ -146,6 +142,7 @@ CREATE TRIGGER tr2_bi BEFORE INSERT ON t
 SELECT trigger_name, created, action_order FROM information_schema.triggers WHERE trigger_schema='test';
 
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 
 --echo #
 --echo # Test 8.
@@ -160,6 +157,7 @@ CREATE TRIGGER tr1_bi BEFORE INSERT ON t
 SHOW CREATE TRIGGER tr1_bi;
 
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 
 --echo #
 --echo # Test 9.
@@ -174,6 +172,7 @@ CREATE TRIGGER tr1_bi BEFORE INSERT ON t
 SHOW TRIGGERS;
 
 DROP TABLE t1;
+SET TIMESTAMP=DEFAULT;
 
 --echo #
 --echo # Test 10.
@@ -317,6 +316,56 @@ CREATE TRIGGER tr1_ai AFTER INSERT ON t1
 SHOW TRIGGERS;
 
 DROP TABLE t1;
+
+# Binlog is required
+--source include/have_log_bin.inc
+
+--echo #
+--echo # Test 17. Check that table's triggers are dumped correctly.
+--echo #
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3;
+
+# dump tables and triggers
+--exec $MYSQL_DUMP --compact test
+disable_query_log;
+DROP TABLE t1;
+
+--echo #
+--echo # Test 18. Check that table's triggers are dumped in right order
+--echo #          taking into account the PRECEDES/FOLLOWS clauses.
+--echo #
+enable_query_log;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi SET @a:=0;
+CREATE TRIGGER tr1_1_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=0;
+
+--echo # Expected order of triggers in the dump is: tr0_bi, tr1_bi, tr1_1_bi, tr2_i.
+# dump tables and triggers
+--exec $MYSQL_DUMP --compact test
+disable_query_log;
+DROP TABLE t1;
+
+--echo #
+--echo # Test 19. Check that table's triggers are dumped correctly in xml.
+--echo #
+enable_query_log;
+CREATE TABLE t1 (a INT);
+SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:00');
+CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2;
+CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3;
+SET TIMESTAMP=DEFAULT;
+
+# dump tables and triggers
+--exec $MYSQL_DUMP --compact --no-create-info --xml test
+disable_query_log;
+DROP TABLE t1;
+
 --echo #
 --echo # End of tests.
 --echo #

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2013-03-15 15:40:59 +0000
+++ b/sql/CMakeLists.txt	2013-04-16 09:51:18 +0000
@@ -168,7 +168,7 @@ SET(SQL_SHARED_SOURCES
   trigger.cc
   trigger_creation_ctx.cc
   trigger_loader.cc
-  triggers_chain.cc
+  trigger_chain.cc
   tztime.cc
   uniques.cc
   unireg.cc

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2013-03-15 15:40:59 +0000
+++ b/sql/partition_info.cc	2013-04-16 09:51:18 +0000
@@ -26,7 +26,7 @@
 #include "table.h"                            // TABLE_LIST
 #include "my_bitmap.h"                        // bitmap*
 #include "sql_base.h"                         // fill_record
-#include "triggers_chain.h"
+#include "trigger_chain.h"
 
 #ifdef WITH_PARTITION_STORAGE_ENGINE
 #include "ha_partition.h"
@@ -298,12 +298,12 @@ bool partition_info::can_prune_insert(TH
   */
   if (table->triggers)
   {
-    Triggers_chain *triggers_chain=
+    Trigger_chain *trigger_chain=
         table->triggers->get_triggers(TRG_EVENT_INSERT,
                                       TRG_ACTION_BEFORE);
 
-    if (triggers_chain &&
-        triggers_chain->is_fields_updated_in_trigger(&full_part_field_set))
+    if (trigger_chain &&
+        trigger_chain->is_fields_updated_in_trigger(&full_part_field_set))
       DBUG_RETURN(false);
   }
 
@@ -350,12 +350,12 @@ bool partition_info::can_prune_insert(TH
     */
     if (table->triggers)
     {
-      Triggers_chain *triggers_chain=
+      Trigger_chain *trigger_chain=
           table->triggers->get_triggers(TRG_EVENT_UPDATE,
                                         TRG_ACTION_BEFORE);
 
-      if (triggers_chain &&
-          triggers_chain->is_fields_updated_in_trigger(&full_part_field_set))
+      if (trigger_chain &&
+          trigger_chain->is_fields_updated_in_trigger(&full_part_field_set))
         DBUG_RETURN(false);
     }
   }

=== modified file 'sql/sp_instr.cc'
--- a/sql/sp_instr.cc	2013-03-28 13:48:31 +0000
+++ b/sql/sp_instr.cc	2013-04-16 09:51:18 +0000
@@ -30,7 +30,7 @@
 
 #include <algorithm>
 
-#include "triggers_chain.h"
+#include "trigger_chain.h"
 #include "table_trigger_dispatcher.h"
 
 ///////////////////////////////////////////////////////////////////////////
@@ -519,10 +519,10 @@ LEX *sp_lex_instr::parse_expr(THD *thd, 
       */
 
       Table_trigger_dispatcher *ttl= sp->m_trg_list;
-      Triggers_chain *triggers_chain=
+      Trigger_chain *trigger_chain=
           ttl->get_triggers(sp->m_trg_chistics.event,
                             sp->m_trg_chistics.action_time);
-      triggers_chain->setup_fields(thd, ttl, thd->lex->sphead);
+      trigger_chain->setup_fields(thd, ttl, thd->lex->sphead);
     }
 
     // Call after-parsing callback.

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2013-04-09 04:40:07 +0000
+++ b/sql/sql_show.cc	2013-04-18 08:02:16 +0000
@@ -56,7 +56,7 @@
 #include "sql_tmp_table.h" // Tmp tables
 #include "sql_optimizer.h" // JOIN
 #include "global_threads.h"
-#include "triggers_chain.h"
+#include "trigger_chain.h"
 
 #include <algorithm>
 using std::max;
@@ -5649,11 +5649,8 @@ static bool store_trigger(THD *thd, TABL
     epoche_timestamp.tv_sec= *created_timestamp / 1000;
     epoche_timestamp.tv_usec= (*created_timestamp % 1000) * 1000;
 
-    MYSQL_TIME timestamp;
-    my_tz_UTC->gmt_sec_to_TIME(&timestamp, epoche_timestamp);
-
     table->field[16]->set_notnull();
-    table->field[16]->store_time(&timestamp, 2);
+    table->field[16]->store_timestamp(&epoche_timestamp);
   }
   sql_mode_string_representation(thd, sql_mode, &sql_mode_rep);
   table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
@@ -5698,13 +5695,13 @@ static int get_schema_triggers_record(TH
     {
       for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
       {
-        Triggers_chain *triggers_chain=
+        Trigger_chain *trigger_chain=
             triggers->get_triggers((trg_event_type)event,
                                    (trg_action_time_type)timing);
-        if (!triggers_chain)
+        if (!trigger_chain)
           continue;
 
-        List_iterator<Trigger> it(triggers_chain->get_triggers());
+        List_iterator<Trigger> it(trigger_chain->get_triggers());
         Trigger *trigger= it++;
         while (trigger)
         {
@@ -8288,7 +8285,7 @@ static bool show_create_trigger_impl(THD
     epoche_timestamp.tv_sec= *created_timestamp / 1000;
     epoche_timestamp.tv_usec= (*created_timestamp % 1000) * 1000;
     MYSQL_TIME timestamp;
-    my_tz_UTC->gmt_sec_to_TIME(&timestamp, epoche_timestamp);
+    my_tz_SYSTEM->gmt_sec_to_TIME(&timestamp, epoche_timestamp);
     p->store(&timestamp, 2);
   }
   else

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2013-03-15 15:40:59 +0000
+++ b/sql/sql_yacc.yy	2013-04-17 12:02:57 +0000
@@ -1022,6 +1022,7 @@ bool match_authorized_user(Security_cont
   List<Condition_information_item> *cond_info_list;
   bool is_not_empty;
   Set_signal_information *signal_item_list;
+  enum trg_action_order_type trigger_action_order_type;
   struct
   {
     enum trg_action_order_type action_order_info;
@@ -1731,7 +1732,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         opt_natural_language_mode opt_query_expansion
         opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
         ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
-        trigger_action_order trg_action_time trg_event
+        trg_action_time trg_event
 
 /*
   Bit field of MYSQL_START_TRANS_OPT_* flags.
@@ -1940,6 +1941,7 @@ END_OF_INPUT
 %type <signal_item_list> opt_set_signal_information;
 
 %type <trg_characteristics> trigger_follows_precedes_clause;
+%type <trigger_action_order_type> trigger_action_order; 
 
 %type <NONE>
         '-' '+' '*' '/' '%' '(' ')'
@@ -16072,7 +16074,7 @@ trigger_follows_precedes_clause: 
           |
             trigger_action_order ident_or_text
             {
-              $$.action_order_info= static_cast<trg_action_order_type>($1);
+              $$.action_order_info= $1;
               $$.anchor_trigger_name= $2;
             }
           ;
@@ -16114,7 +16116,7 @@ trigger_tail:
 
             sp->m_trg_chistics.action_time= (enum trg_action_time_type) $4;
             sp->m_trg_chistics.event= (enum trg_event_type) $5;
-            sp->m_trg_chistics.action_order_info= (enum trg_action_order_type) $15.action_order_info;
+            sp->m_trg_chistics.action_order_info= $15.action_order_info;
             sp->m_trg_chistics.anchor_trigger_name= $15.anchor_trigger_name;
             lex->stmt_definition_begin= $2;
             lex->ident.str= $7;

=== modified file 'sql/table_trigger_dispatcher.cc'
--- a/sql/table_trigger_dispatcher.cc	2013-04-15 06:28:05 +0000
+++ b/sql/table_trigger_dispatcher.cc	2013-04-17 09:31:10 +0000
@@ -21,7 +21,7 @@
 
 #include "my_global.h"
 #include "table_trigger_dispatcher.h"
-#include "triggers_chain.h"
+#include "trigger_chain.h"
 
 #include "sql_priv.h"
 #include "unireg.h"
@@ -517,11 +517,11 @@ bool Table_trigger_dispatcher::setup_tri
     if (t->has_parse_error())
       continue;
 
-    Triggers_chain *triggers_chain= get_triggers_chain(t->get_event(),
-                                                       t->get_action_time());
+    Trigger_chain *trigger_chain= get_trigger_chain(t->get_event(),
+                                                    t->get_action_time());
 
-    if (!triggers_chain ||
-        triggers_chain->add_trigger(t, &trigger_table->mem_root))
+    if (!trigger_chain ||
+        trigger_chain->add_trigger(t, &trigger_table->mem_root))
       return true;
 
     if (!names_only)
@@ -718,10 +718,10 @@ Trigger* Table_trigger_dispatcher::creat
   trg_event_type event_type= lex->sphead->m_trg_chistics.event;
   trg_action_time_type action_time= lex->sphead->m_trg_chistics.action_time;
 
-  Triggers_chain *triggers_chain= get_triggers_chain(event_type,
-                                                     action_time);
+  Trigger_chain *trigger_chain= get_trigger_chain(event_type,
+                                                  action_time);
 
-  if (!triggers_chain)
+  if (!trigger_chain)
     return NULL;
 
   switch (action_order_info)
@@ -729,7 +729,7 @@ Trigger* Table_trigger_dispatcher::creat
   case TRG_ACTION_ORDER_NONE:
   {
     ulonglong next_action_order_value=
-        triggers_chain->get_next_action_order_id();
+        trigger_chain->get_next_action_order_id();
 
     new_trigger= new (&table->mem_root) Trigger(&trigger_table->s->db,
                                                 &trigger_table->s->table_name,
@@ -759,8 +759,8 @@ Trigger* Table_trigger_dispatcher::creat
     const char *trigger_name_to_find=
         lex->sphead->m_trg_chistics.anchor_trigger_name.str;
 
-    if (triggers_chain->check_referenced_trigger_exist(trigger_name_to_find,
-                                                       action_order_info))
+    if (trigger_chain->check_referenced_trigger_exist(trigger_name_to_find,
+                                                      action_order_info))
     {
       my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
       return NULL;
@@ -876,8 +876,8 @@ ulonglong Table_trigger_dispatcher::comp
   }
   else
   {
-    Triggers_chain *triggers_chain= get_triggers_chain(event_type,
-                                                       action_time);
+    Trigger_chain *trigger_chain= get_trigger_chain(event_type,
+                                                    action_time);
 
     /*
       This branch is executed when the trigger referenced by clauses
@@ -897,7 +897,7 @@ ulonglong Table_trigger_dispatcher::comp
           version of mysql. This trigger has action_order=0.
           2. user creates trigger t2_bi FOLLOWS t1_bi. action_order
           for t2_bi is computed using internal sequence generator
-          (stared from 1) and for this trigger has value 1. Next time
+          (started from 1) and for this trigger has value 1. Next time
           when we need to generate new action_order value it will have
           value 2.
           3. user creates trigger t0_bi PRECEDES t1_bi. If we didn't
@@ -906,11 +906,11 @@ ulonglong Table_trigger_dispatcher::comp
           t1_bi.action_value = 3, t2_bi.action_value = 4.
           It isn't what the user is expected.
       */
-      triggers_chain->reset_next_action_order_id();
+      trigger_chain->reset_next_action_order_id();
     }
 
     next_action_order_value=
-        triggers_chain->get_next_action_order_id();
+        trigger_chain->get_next_action_order_id();
   }
 
   return next_action_order_value;
@@ -932,24 +932,24 @@ ulonglong Table_trigger_dispatcher::comp
     != NULL success
 */
 
-Triggers_chain* Table_trigger_dispatcher::get_triggers_chain(
+Trigger_chain* Table_trigger_dispatcher::get_trigger_chain(
     trg_event_type trg_event,
     trg_action_time_type trg_action_time)
 {
   DBUG_ASSERT(trg_event != TRG_EVENT_MAX &&
               trg_action_time != TRG_ACTION_MAX);
 
-  Triggers_chain *triggers_chain=
+  Trigger_chain *trigger_chain=
       m_trigger_map[trg_event][trg_action_time];
 
-  if (!triggers_chain)
+  if (!trigger_chain)
   {
-    triggers_chain= new (&trigger_table->mem_root) Triggers_chain();
-    if (triggers_chain)
-      m_trigger_map[trg_event][trg_action_time]= triggers_chain;
+    trigger_chain= new (&trigger_table->mem_root) Trigger_chain();
+    if (trigger_chain)
+      m_trigger_map[trg_event][trg_action_time]= trigger_chain;
   }
 
-  return triggers_chain;
+  return trigger_chain;
 }
 
 
@@ -1293,8 +1293,8 @@ void Table_trigger_dispatcher::parse_tri
         Remember the parse error message
         (only the 1st error message will be remembered).
       */
-
-      set_parse_error_message(t->get_parse_error_message());
+      if (t->has_parse_error())
+        set_parse_error_message(t->get_parse_error_message());
 
       if (result)
       {
@@ -1304,11 +1304,6 @@ void Table_trigger_dispatcher::parse_tri
           'CREATE TRIGGER trg1 ...'  the trigger definition contains
           the string 'bla-bla-bla'. In this case we remove the trigger object
           from the list.
-
-          TODO: XXX: FIXME: that seems to be not the case.
-          result is true when parse_trigger_body() returns true.
-          And parse_trigger_body() returns true when OOM happens,
-          not when the parsing failed.
         */
 
         delete t;
@@ -1352,12 +1347,12 @@ bool Table_trigger_dispatcher::process_t
                                                 trg_action_time_type action_time,
                                                 bool old_row_is_record1)
 {
-  Triggers_chain *triggers_chain= get_triggers(event, action_time);
+  Trigger_chain *trigger_chain= get_triggers(event, action_time);
 
   if (check_for_broken_triggers())
     return true;
 
-  if (triggers_chain == NULL)
+  if (trigger_chain == NULL)
     return false;
 
   if (old_row_is_record1)
@@ -1377,7 +1372,7 @@ bool Table_trigger_dispatcher::process_t
   DBUG_ASSERT(trigger_table->pos_in_table_list->trg_event_map &
               static_cast<uint>(1 << static_cast<int>(event)));
 
-  return triggers_chain->execute_triggers(thd);
+  return trigger_chain->execute_triggers(thd);
 }
 
 
@@ -1415,13 +1410,13 @@ bool Table_trigger_dispatcher::add_table
         trg_event_type trg_event= (trg_event_type) i;
         trg_action_time_type trg_action_time = (trg_action_time_type) j;
 
-        Triggers_chain *triggers_chain=
+        Trigger_chain *trigger_chain=
           table_list->table->triggers->get_triggers(trg_event,
                                                     trg_action_time);
 
-        if (triggers_chain)
-          triggers_chain->add_tables_and_routines(thd, prelocking_ctx,
-                                                  table_list);
+        if (trigger_chain)
+          trigger_chain->add_tables_and_routines(thd, prelocking_ctx,
+                                                 table_list);
       }
     }
   }
@@ -1519,12 +1514,12 @@ void Table_trigger_dispatcher::mark_fiel
 {
   for (int i= 0; i < (int) TRG_ACTION_MAX; ++i)
   {
-    Triggers_chain *triggers_chain= get_triggers(event, (trg_action_time_type) i);
+    Trigger_chain *trigger_chain= get_triggers(event, (trg_action_time_type) i);
 
-    if (!triggers_chain)
+    if (!trigger_chain)
       continue;
 
-    triggers_chain->mark_field_used(trigger_table);
+    trigger_chain->mark_field_used(trigger_table);
   }
 
   trigger_table->file->column_bitmaps_signal();

=== modified file 'sql/table_trigger_dispatcher.h'
--- a/sql/table_trigger_dispatcher.h	2013-04-09 05:43:59 +0000
+++ b/sql/table_trigger_dispatcher.h	2013-04-17 09:31:10 +0000
@@ -31,7 +31,7 @@ struct TABLE_LIST;
 class sp_name;
 class Query_tables_list;
 class Trigger;
-class Triggers_chain;
+class Trigger_chain;
 
 ///////////////////////////////////////////////////////////////////////////
 
@@ -46,7 +46,7 @@ private:
   List<Trigger> m_triggers;
 
   /// Triggers grouped by event, action_time.
-  Triggers_chain *m_trigger_map[TRG_EVENT_MAX][TRG_ACTION_MAX];
+  Trigger_chain *m_trigger_map[TRG_EVENT_MAX][TRG_ACTION_MAX];
 
   /**
     Copy of TABLE::Field array with field pointers set to TABLE::record[1]
@@ -70,12 +70,14 @@ private:
      safe to add triggers since we don't know if the broken trigger has the
      same name or event type. Nor is it safe to invoke any trigger for the
      aforementioned reasons. The only safe operations are drop_trigger and
-     drop_all_triggers.
+     drop_all_triggers. We can't use the value of m_parse_error_message
+     as a flag to inform that some trigger has a parse error since for
+     multi-byte locale the first byte of message can be 0 but the message
+     still be meaningful. It means that just a comparison against
+     m_parse_error_message[0] couldn't be done safely.
 
      @see Table_trigger_dispatcher::set_parse_error
-
-    FIXME: get rid of this flag.
-   */
+  */
   bool m_has_unparseable_trigger;
 
   /**
@@ -149,6 +151,7 @@ public:
     trigger_table(table)
   {
     memset(m_trigger_map, 0, sizeof(m_trigger_map));
+    m_parse_error_message[0]= 0;
   }
 
   ~Table_trigger_dispatcher();
@@ -161,14 +164,14 @@ public:
                         trg_action_time_type action_time,
                         bool old_row_is_record1);
 
-  Triggers_chain *get_triggers(trg_event_type event,
-                               trg_action_time_type action_time)
+  Trigger_chain *get_triggers(trg_event_type event,
+                              trg_action_time_type action_time)
   {
     return m_trigger_map[event][action_time];
   }
 
-  const Triggers_chain *get_triggers(trg_event_type event,
-                                     trg_action_time_type action_time) const
+  const Trigger_chain *get_triggers(trg_event_type event,
+                                    trg_action_time_type action_time) const
   {
     return m_trigger_map[event][action_time];
   }
@@ -248,8 +251,8 @@ private:
       trg_event_type event_type,
       trg_action_time_type action_time);
 
-  Triggers_chain* get_triggers_chain(trg_event_type trg_event,
-                                     trg_action_time_type trg_action_time);
+  Trigger_chain* get_trigger_chain(trg_event_type trg_event,
+                                   trg_action_time_type trg_action_time);
 
   Trigger* find_right_place_for_new_trigger(
       const char *trigger_name_to_find,

=== modified file 'sql/trigger.cc'
--- a/sql/trigger.cc	2013-04-09 05:15:21 +0000
+++ b/sql/trigger.cc	2013-04-16 12:27:37 +0000
@@ -26,7 +26,6 @@
 #include "table.h" // TABLE_LIST
 #include "sp.h" // sp_update_stmt_used_routines, sp_add_used_routine
 
-
 /**
   An error handler that catches all non-OOM errors which can occur during
   parsing of trigger body. Such errors are ignored and corresponding error

=== modified file 'sql/trigger.h'
--- a/sql/trigger.h	2013-04-09 05:15:21 +0000
+++ b/sql/trigger.h	2013-04-17 09:31:10 +0000
@@ -18,11 +18,19 @@
 #define TRIGGER_H_INCLUDED
 
 ///////////////////////////////////////////////////////////////////////////
+#include "my_global.h"
+#include "sql_alloc.h"
+#include "mysql_com.h"
 
 struct GRANT_INFO;
 
 class sp_head;
 class Stored_program_creation_ctx;
+class TABLE;
+class Query_tables_list;
+class Table_trigger_dispatcher;
+
+typedef ulonglong sql_mode_t;
 
 /** Event on which trigger is invoked. */
 enum trg_event_type
@@ -55,18 +63,6 @@ enum trg_action_order_type
   TRG_ACTION_ORDER_MAX
 };
 
-#include "my_global.h"
-#include "sql_alloc.h"
-#include "m_string.h"  // LEX_STRING
-#include "table.h"     // TABLE
-#include "my_bitmap.h" // MY_BITMAP
-
-class Query_tables_list;
-
-// FIXME: remove it.
-typedef ulonglong sql_mode_t;
-
-
 /**
   This is a class that represents a trigger entity.
   Trigger can be created, initialized, parsed and executed.
@@ -104,6 +100,7 @@ public:
     m_created_timestamp_is_set(created_timestamp != NULL),
     m_action_order(action_order)
   {
+    m_parse_error_message[0]= 0;
     memset(&m_subject_table_grant, 0, sizeof (m_subject_table_grant));
   }
 
@@ -260,45 +257,81 @@ private:
   /**
     "ON table_name" part in trigger definition, used for
     updating trigger definition during RENAME TABLE.
+    Allocated on TABLE's mem_root.
   */
   LEX_STRING *m_on_table_name;
 
   /// Grant information for the trigger.
   GRANT_INFO m_subject_table_grant;
 
-  /// Trigger definition to save in TRG-file.
+  /// Trigger definition to save in TRG-file. Allocated on TABLE's mem_root.
   LEX_STRING *m_definition;
 
   /// Trigger sql-mode.
   sql_mode_t m_sql_mode;
 
-  /// Trigger definer.
+  /// Trigger definer. Allocated on TABLE's mem_root.
   LEX_STRING *m_definer;
 
-  /*
+  /**
     Character set context, used for parsing and executing trigger.
+    Allocated on TABLE's mem_root.
   */
   LEX_STRING *m_client_cs_name;
+  /**
+    Collation name of the connection within one a trigger are created.
+    Allocated on TABLE's mem_root.
+  */
   LEX_STRING *m_connection_cl_name;
+  /**
+    Default database collation.
+    Allocated on TABLE's mem_root.
+  */
   LEX_STRING *m_db_cl_name;
+  /**
+    Pointer to the sp_head corresponding to the trigger.
+  */
   sp_head *m_sp;
 
+  /**
+    Trigger action time.
+  */
   trg_action_time_type m_action_time;
+
+  /**
+    Trigger event.
+  */
   trg_event_type m_event;
 
+  /**
+    This flags specifies whether the trigger has parse error or not.
+  */
   bool m_has_parse_error;
 
-  /*
+  /**
     This error will be displayed when the user tries to manipulate or invoke
     triggers on a table that has broken triggers. It will get set only once
     per statement and thus will contain the first parse error encountered in
     the trigger file.
-   */
+  */
   char m_parse_error_message[MYSQL_ERRMSG_SIZE];
 
+  /**
+    Current time when the trigger was created (measured in milliseconds since
+    since 0 hours, 0 minutes, 0 seconds, January 1, 1970, UTC.
+  */
   longlong m_created_timestamp;
+
+  /**
+    Boolean flag whether timestamp was set or not.
+  */
   bool m_created_timestamp_is_set;
 
+  /**
+    Action_order value for the trigger. Action_order is the ordinal position
+    of the trigger in the list of triggers with the same EVENT_MANIPULATION,
+    CONDITION_TIMING, and ACTION_ORIENTATION.
+  */
   ulonglong m_action_order;
 };
 

=== renamed file 'sql/triggers_chain.cc' => 'sql/trigger_chain.cc'
--- a/sql/triggers_chain.cc	2013-03-28 13:48:31 +0000
+++ b/sql/trigger_chain.cc	2013-04-16 12:27:37 +0000
@@ -1,9 +1,130 @@
-#include "triggers_chain.h"
+#include "my_global.h"
+#include "sql_class.h"
+
+#include "trigger_chain.h"
 #include "table_trigger_dispatcher.h"
 #include "sp_head.h"
+#include "table.h"
+#include "sql_list.h"
+
+/**
+  Add a new trigger into the list of triggers with the same
+  ACTION/TIMING value combination.
+
+  @param thd           current thread context
+  @param table_mem_root  table's MEM_ROOT for allocation
+
+  @return operation status
+  @retval
+    false  success
+    true   failure (OOM)
+*/
+
+bool Trigger_chain::add_trigger(Trigger *new_trigger, MEM_ROOT *table_mem_root)
+{
+  if (m_triggers.push_back(new_trigger, table_mem_root))
+    return true; // OOM
+
+  ulonglong action_order= new_trigger->get_action_order();
+
+  if (action_order > get_next_action_order_id())
+    set_next_action_order_id(action_order + 1);
+
+  return false;
+}
+
+
+/**
+  Run every trigger in the list of triggers.
+
+  @param thd
+  @return  Result of trigger execution
+    @retval false  all triggers in the list were executed successfully.
+    @retval true   some trigger was failed. We stop triggers execution
+                   on the first failed trigger and don't attempt to finish
+                   the rest of triggers located after the failed one.
+*/
+
+bool Trigger_chain::execute_triggers(THD *thd)
+{
+  List_iterator<Trigger> it(m_triggers);
+  Trigger *next_trigger= it++;
+  while (next_trigger)
+  {
+    if (next_trigger->execute(thd))
+      return true;
+    next_trigger= it++;
+  }
+  return false;
+}
+
+
+/**
+  Iterate over the list of triggers and add tables and routines used by trigger
+  to the set of elements used by statement.
+
+  @param [in]     thd               thread handle
+  @param [in out] prelocking_ctx    prelocking context of the statement
+  @param [in]     table_list        TABLE_LIST for the table
+*/
+
+void Trigger_chain::add_tables_and_routines(THD *thd,
+                                            Query_tables_list *prelocking_ctx,
+                                            TABLE_LIST *table_list)
+{
+  List_iterator<Trigger> it(m_triggers);
+  Trigger *next_trigger= it++;
+  while (next_trigger)
+  {
+    next_trigger->add_tables_and_routines(thd, prelocking_ctx, table_list);
+    next_trigger= it++;
+  }
+}
+
+
+/**
+  Iterate over the list of triggers and mark fields of subject table
+  which we read/set in every trigger.
+
+  @param [in] trigger_table    pointer to the trigger's table
+*/
+void Trigger_chain::mark_field_used(TABLE *trigger_table)
+{
+  List_iterator<Trigger> it(m_triggers);
+  Trigger *next_trigger= it++;
+  while (next_trigger)
+  {
+    next_trigger->mark_field_used(trigger_table);
+    next_trigger= it++;
+  }
+}
+
+/**
+  Iterate over the list of triggers and check whether some
+  table's fields are used in any trigger.
+
+  @param [in] used_fields       bitmap of fields to check
+
+  @return Check result
+    @retval true   Some table fields are used in trigger
+    @retval false  None of table fields are used in trigger
+*/
+
+bool Trigger_chain::is_fields_updated_in_trigger(const MY_BITMAP *used_fields)
+{
+  List_iterator<Trigger> it(m_triggers);
+  Trigger *next_trigger= it++;
+  while (next_trigger)
+  {
+    if (next_trigger->is_fields_updated_in_trigger(used_fields))
+      return true;
+    next_trigger= it++;
+  }
+  return false;
+}
 
-void Triggers_chain::setup_fields(THD *thd, Table_trigger_dispatcher *ttl,
-                                  const sp_head *sp)
+void Trigger_chain::setup_fields(THD *thd, Table_trigger_dispatcher *ttl,
+                                 const sp_head *sp)
 {
   List_iterator<Trigger> it(m_triggers);
   Trigger *next_trigger= it++;
@@ -43,7 +164,7 @@ void Triggers_chain::setup_fields(THD *t
     false Trigger was found
 */
 
-bool Triggers_chain::check_referenced_trigger_exist(
+bool Trigger_chain::check_referenced_trigger_exist(
     const char *trigger_name_to_find,
     trg_action_order_type action_order_info)
 {

=== renamed file 'sql/triggers_chain.h' => 'sql/trigger_chain.h'
--- a/sql/triggers_chain.h	2013-04-09 04:34:00 +0000
+++ b/sql/trigger_chain.h	2013-04-16 12:27:37 +0000
@@ -1,111 +1,31 @@
-#ifndef TRIGGERS_CHAIN_H_INCLUDED
-#define TRIGGERS_CHAIN_H_INCLUDED
-
-#include "my_global.h"
-#include "sql_priv.h"
-#include "sql_alloc.h"
-#include "sql_class.h"
+#ifndef TRIGGER_CHAIN_H_INCLUDED
+#define TRIGGER_CHAIN_H_INCLUDED
 
 #include "trigger.h"
-#include "table.h"
 #include "my_bitmap.h"
-#include "sql_list.h"
 
+class THD;
+class sp_head;
 class Table_trigger_dispatcher;
 
-class Triggers_chain : public Sql_alloc
+class Trigger_chain : public Sql_alloc
 {
 public:
-  Triggers_chain()
+  Trigger_chain()
   : next_action_order(1)
   {}
 
-  /**
-    Add a new trigger into the list of triggers with the same
-    ACTION/TIMING value combination.
-
-    @param thd           current thread context
-    @param table_mem_root  table's MEM_ROOT for allocation
-
-    @return operation status
-    @retval
-      false  success
-      true   failure (OOM)
-  */
-
-  bool add_trigger(Trigger *new_trigger, MEM_ROOT *table_mem_root)
-  {
-    if (m_triggers.push_back(new_trigger, table_mem_root))
-      return true; // OOM
+  bool add_trigger(Trigger *new_trigger, MEM_ROOT *table_mem_root);
 
-    ulonglong action_order= new_trigger->get_action_order();
-
-    if (action_order > get_next_action_order_id())
-      set_next_action_order_id(action_order + 1);
-
-    return false;
-  }
-
-  /**
-    Run every trigger in the list of triggers.
-
-    @param thd
-    @return  Result of trigger execution
-      @retval false  all triggers in the list were executed successfully.
-      @retval true   some trigger was failed. We stop triggers execution
-                     on the first failed trigger and don't attempt to finish
-                     the rest of triggers located after the failed one.
-  */
-
-  bool execute_triggers(THD *thd)
-  {
-    List_iterator<Trigger> it(m_triggers);
-    Trigger *next_trigger= it++;
-    while (next_trigger)
-    {
-      if (next_trigger->execute(thd))
-        return true;
-      next_trigger= it++;
-    }
-    return false;
-  }
+  bool execute_triggers(THD *thd);
 
   void add_tables_and_routines(THD *thd,
                                Query_tables_list *prelocking_ctx,
-                               TABLE_LIST *table_list)
-  {
-    List_iterator<Trigger> it(m_triggers);
-    Trigger *next_trigger= it++;
-    while (next_trigger)
-    {
-      next_trigger->add_tables_and_routines(thd, prelocking_ctx, table_list);
-      next_trigger= it++;
-    }
-  }
+                               TABLE_LIST *table_list);
 
-  void mark_field_used(TABLE *trigger_table)
-  {
-    List_iterator<Trigger> it(m_triggers);
-    Trigger *next_trigger= it++;
-    while (next_trigger)
-    {
-      next_trigger->mark_field_used(trigger_table);
-      next_trigger= it++;
-    }
-  }
+  void mark_field_used(TABLE *trigger_table);
 
-  bool is_fields_updated_in_trigger(const MY_BITMAP *used_fields)
-  {
-    List_iterator<Trigger> it(m_triggers);
-    Trigger *next_trigger= it++;
-    while (next_trigger)
-    {
-      if (next_trigger->is_fields_updated_in_trigger(used_fields))
-        return true;
-      next_trigger= it++;
-    }
-    return false;
-  }
+  bool is_fields_updated_in_trigger(const MY_BITMAP *used_fields);
 
   void setup_fields(THD *thd, Table_trigger_dispatcher *ttl,
                     const sp_head *sp);
@@ -141,6 +61,9 @@ private:
   */
   ulonglong next_action_order;
 
+  /**
+    List of triggers to execute.
+  */
   List<Trigger> m_triggers;
 };
 

=== modified file 'sql/trigger_loader.cc'
--- a/sql/trigger_loader.cc	2013-04-09 04:58:03 +0000
+++ b/sql/trigger_loader.cc	2013-04-16 12:27:37 +0000
@@ -71,11 +71,6 @@ static File_option trn_file_parameters[]
 
 struct Trigger_data
 {
-  Trigger_data()
-  : default_creation_timestamp(0),
-    default_action_order(0)
-  {}
-
   /// List of CREATE TRIGGER statements.
   List<LEX_STRING>  definitions_list;
 
@@ -97,12 +92,10 @@ struct Trigger_data
   /// List of trigger creation time stamps
   List<longlong> created_timestamps;
 
-  longlong default_creation_timestamp;
+  static longlong default_creation_timestamp;
   /// List of trigger action orders
   List<ulonglong> action_orders;
 
-  ulonglong default_action_order;
-
   bool append_trigger(Trigger *t, MEM_ROOT *mem_root)
   {
     longlong *created_timestamp= t->get_created_timestamp();
@@ -121,6 +114,7 @@ struct Trigger_data
   }
 };
 
+longlong Trigger_data::default_creation_timestamp= 0;
 ///////////////////////////////////////////////////////////////////////////
 
 /**

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (Dmitry.Shulga:5412 to 5419) WL#3253Dmitry Shulga20 May