From 8be53a389c8eebed337057fa366b7c4506ba16b1 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 2 Oct 2016 15:35:08 +0300 Subject: [PATCH] MDEV-6112 multiple triggers per table This is similar to MysQL Worklog 3253, but with a different implementation. The disk format and SQL syntax is identical with MySQL 5.7. Fetures supported: - "Any" ammount of any trigger - Supports FOLLOWS and PRECEDES to be able to put triggers in a certain execution order. Implementation details: - Class Trigger added to hold information about a trigger. Before this trigger information was stored in a set of lists in Table_triggers_list and in Table_triggers_list::bodies - Each Trigger has a next field that poinst to the next Trigger with the same action and time. - When accessing a trigger, we now always access all linked triggers - The list are now only used to load and save trigger files. - MySQL trigger test case (trigger_wl3253) added and we execute these identically. - Even more gracefully handling of wrong trigger files than before. This is useful if a trigger file uses functions or syntax not provided by the server. - Each trigger now has a "Created" field that shows when the trigger was created, with 2 decimals. Other comments: - Many of the changes in test files was done because of the new "Created" field in the trigger file. This shows up in SHOW ... TRIGGER and when using information_schema.trigger. - Don't check if all memory is released if on uses --gdb; This is needed to be able to get a list from safemalloc of not freed memory while debugging. - Added option to trim_whitespace() to know how many prefix characters was skipped. - Changed a few ulonglong sql_mode to sql_mode_t, to find some wrong usage of sql_mode. --- mysql-test/extra/rpl_tests/rpl_ddl.test | 2 + .../include/ddl_i18n.check_triggers.inc | 6 + mysql-test/r/create.result | 1 - mysql-test/r/create_drop_trigger.result | 1 - mysql-test/r/ddl_i18n_koi8r.result | 96 +- mysql-test/r/ddl_i18n_utf8.result | 96 +- mysql-test/r/features.result | 2 +- mysql-test/r/information_schema.result | 20 +- mysql-test/r/merge.result | 4 +- mysql-test/r/mysql_comments.result | 16 +- mysql-test/r/mysqlcheck.result | 8 +- mysql-test/r/mysqldump.result | 20 +- mysql-test/r/show_check.result | 105 +- mysql-test/r/trigger-compat.result | 30 +- mysql-test/r/trigger.result | 57 +- mysql-test/r/trigger_notembedded.result | 14 +- mysql-test/r/trigger_wl3253.result | 502 ++++++ .../suite/binlog/r/binlog_trigger.result | 24 + mysql-test/suite/binlog/t/binlog_trigger.test | 23 + .../suite/funcs_1/datadict/is_triggers.inc | 11 + .../suite/funcs_1/r/innodb_trig_03e.result | 4 +- .../suite/funcs_1/r/innodb_trig_0407.result | 24 +- .../suite/funcs_1/r/is_columns_is.result | 4 +- .../funcs_1/r/is_columns_is_embedded.result | 4 +- mysql-test/suite/funcs_1/r/is_triggers.result | 26 +- .../suite/funcs_1/r/memory_trig_03e.result | 4 +- .../suite/funcs_1/r/memory_trig_0407.result | 24 +- .../suite/funcs_1/r/myisam_trig_03e.result | 4 +- .../suite/funcs_1/r/myisam_trig_0407.result | 24 +- .../triggers/triggers_03e_db_table_mix.inc | 2 + .../triggers/triggers_03e_global_db_mix.inc | 1 + .../funcs_1/triggers/triggers_03e_prepare.inc | 1 + .../triggers/triggers_03e_table_level.inc | 4 + .../suite/funcs_1/triggers/triggers_0407.inc | 44 +- mysql-test/suite/roles/definer.result | 16 +- mysql-test/suite/roles/definer.test | 4 + mysql-test/suite/rpl/r/rpl_ddl.result | 4 +- .../suite/rpl/r/rpl_replicate_do.result | 6 +- mysql-test/suite/rpl/r/rpl_trigger.result | 45 +- mysql-test/suite/rpl/t/rpl_replicate_do.test | 4 + mysql-test/suite/rpl/t/rpl_trigger.test | 45 + mysql-test/t/create.test | 1 - mysql-test/t/create_drop_trigger.test | 1 - mysql-test/t/features.test | 1 + mysql-test/t/information_schema.test | 4 + mysql-test/t/merge.test | 1 + mysql-test/t/mysql_comments.test | 2 + mysql-test/t/mysqldump.test | 11 +- mysql-test/t/show_check.test | 33 + mysql-test/t/trigger-compat.test | 6 +- mysql-test/t/trigger.test | 44 +- mysql-test/t/trigger_notembedded.test | 2 + mysql-test/t/trigger_wl3253.test | 428 ++++++ sql/item.cc | 2 +- sql/lex.h | 2 + sql/mysqld.cc | 5 +- sql/partition_info.cc | 15 +- sql/partition_info.h | 14 + sql/session_tracker.cc | 6 +- sql/set_var.h | 2 +- sql/share/errmsg-utf8.txt | 2 + sql/sp_head.cc | 7 +- sql/sql_base.h | 2 +- sql/sql_class.h | 4 +- sql/sql_lex.cc | 4 +- sql/sql_lex.h | 13 +- sql/sql_show.cc | 191 +-- sql/sql_trigger.cc | 1362 +++++++++-------- sql/sql_trigger.h | 174 ++- sql/sql_yacc.yy | 49 +- sql/sys_vars.cc | 3 +- sql/table.cc | 2 +- sql/wsrep_mysqld.cc | 3 +- 73 files changed, 2553 insertions(+), 1175 deletions(-) create mode 100644 mysql-test/r/trigger_wl3253.result create mode 100644 mysql-test/suite/binlog/r/binlog_trigger.result create mode 100644 mysql-test/suite/binlog/t/binlog_trigger.test create mode 100644 mysql-test/t/trigger_wl3253.test diff --git a/mysql-test/extra/rpl_tests/rpl_ddl.test b/mysql-test/extra/rpl_tests/rpl_ddl.test index e466a08a541..f11cd979ba8 100644 --- a/mysql-test/extra/rpl_tests/rpl_ddl.test +++ b/mysql-test/extra/rpl_tests/rpl_ddl.test @@ -473,8 +473,10 @@ let $my_stmt= CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; let $my_master_commit= true; let $my_slave_commit= true; --source include/rpl_stmt_seq.inc +--replace_column 6 # SHOW TRIGGERS; connection slave; +--replace_column 6 # SHOW TRIGGERS; connection master; diff --git a/mysql-test/include/ddl_i18n.check_triggers.inc b/mysql-test/include/ddl_i18n.check_triggers.inc index 832ab8091e8..2073021fc9e 100644 --- a/mysql-test/include/ddl_i18n.check_triggers.inc +++ b/mysql-test/include/ddl_i18n.check_triggers.inc @@ -3,12 +3,16 @@ --echo --echo +--replace_column 7 # SHOW CREATE TRIGGER trg1| --echo +--replace_column 7 # SHOW CREATE TRIGGER trg2| --echo +--replace_column 7 # SHOW CREATE TRIGGER mysqltest2.trg3| --echo +--replace_column 7 # SHOW CREATE TRIGGER mysqltest2.trg4| # - Check SHOW statement; @@ -16,6 +20,7 @@ SHOW CREATE TRIGGER mysqltest2.trg4| --echo --echo +--replace_column 6 # SHOW TRIGGERS| --echo @@ -24,6 +29,7 @@ use mysqltest2| --echo +--replace_column 6 # SHOW TRIGGERS| use mysqltest1| diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 36a192c2609..dd10628bce5 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1352,7 +1352,6 @@ CREATE TRIGGER f1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN UPDATE A SET `pk`=1 WHERE `pk`=0 ; END ;| -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' DROP TABLE t1; DROP TABLE B; # diff --git a/mysql-test/r/create_drop_trigger.result b/mysql-test/r/create_drop_trigger.result index a215838b0fd..f7ae8d21a7f 100644 --- a/mysql-test/r/create_drop_trigger.result +++ b/mysql-test/r/create_drop_trigger.result @@ -8,7 +8,6 @@ SELECT @sum; @sum 60 CREATE TRIGGER IF NOT EXISTS val_sum_new BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' CREATE TRIGGER IF NOT EXISTS val_sum AFTER INSERT ON t1 FOR EACH ROW SET @sum = @sum + 1 + NEW.val; Warnings: Note 1359 Trigger already exists diff --git a/mysql-test/r/ddl_i18n_koi8r.result b/mysql-test/r/ddl_i18n_koi8r.result index 8423f8fe367..ba43c1c867f 100644 --- a/mysql-test/r/ddl_i18n_koi8r.result +++ b/mysql-test/r/ddl_i18n_koi8r.result @@ -1198,7 +1198,7 @@ END| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1211,10 +1211,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1227,10 +1227,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1243,10 +1243,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1259,7 +1259,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1275,7 +1275,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -1287,7 +1287,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest2| @@ -1304,7 +1304,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -1316,13 +1316,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1337,7 +1337,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1352,7 +1352,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci u SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1367,7 +1367,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1470,7 +1470,7 @@ use mysqltest1| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1483,10 +1483,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1499,10 +1499,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1515,10 +1515,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1531,7 +1531,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1547,7 +1547,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -1559,7 +1559,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest2| @@ -1576,7 +1576,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -1588,13 +1588,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1609,7 +1609,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1624,7 +1624,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci u SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1639,7 +1639,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -1904,7 +1904,7 @@ use mysqltest1| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1917,10 +1917,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1933,10 +1933,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10); @@ -1949,10 +1949,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = _koi8r 'ิลหำิ'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; @@ -1965,7 +1965,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = _koi8r 'ิลหำิ'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; -END koi8r koi8r_general_ci utf8_unicode_ci +END koi8r koi8r_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1981,7 +1981,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -1993,7 +1993,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest2| @@ -2010,7 +2010,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ิลหำิ'; SET @a1 = 'ิลหำิ'; SET @a2 = 'ิลหำิ'; -END BEFORE NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END BEFORE # root@localhost koi8r koi8r_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); @@ -2022,13 +2022,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ิลหำิ'; SET @b1 = 'ิลหำิ'; SET @b2 = 'ิลหำิ'; -END AFTER NULL root@localhost koi8r koi8r_general_ci utf8_unicode_ci +END AFTER # root@localhost koi8r koi8r_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -2043,7 +2043,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -2058,7 +2058,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci u SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); @@ -2073,7 +2073,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost koi8r koi8r_general_ci SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะลาลอ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะลาลอ1)); INSERT INTO log VALUES(COLLATION('ิลหำิ')); diff --git a/mysql-test/r/ddl_i18n_utf8.result b/mysql-test/r/ddl_i18n_utf8.result index 2c9ea77b809..47786196037 100644 --- a/mysql-test/r/ddl_i18n_utf8.result +++ b/mysql-test/r/ddl_i18n_utf8.result @@ -1198,7 +1198,7 @@ END| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1211,10 +1211,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1227,10 +1227,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1243,10 +1243,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1259,7 +1259,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1275,7 +1275,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -1287,7 +1287,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest2| @@ -1304,7 +1304,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -1316,13 +1316,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1337,7 +1337,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1352,7 +1352,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci utf SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1367,7 +1367,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1470,7 +1470,7 @@ use mysqltest1| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1483,10 +1483,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1499,10 +1499,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1515,10 +1515,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1531,7 +1531,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1547,7 +1547,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -1559,7 +1559,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest2| @@ -1576,7 +1576,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -1588,13 +1588,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1609,7 +1609,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1624,7 +1624,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci utf SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1639,7 +1639,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -1904,7 +1904,7 @@ use mysqltest1| SHOW CREATE TRIGGER trg1| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg1 CREATE DEFINER=`root`@`localhost` TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1917,10 +1917,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER trg2| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg2 CREATE DEFINER=`root`@`localhost` TRIGGER trg2 AFTER INSERT ON t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1933,10 +1933,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg3| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg3 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg3 BEFORE INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); @@ -1949,10 +1949,10 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = _utf8 'ั‚ะตะบัั‚'; SET @a3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW CREATE TRIGGER mysqltest2.trg4| -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created trg4 CREATE DEFINER=`root`@`localhost` TRIGGER mysqltest2.trg4 AFTER INSERT ON mysqltest2.t1 FOR EACH ROW BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; @@ -1965,7 +1965,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = _utf8 'ั‚ะตะบัั‚'; SET @b3 = _koi8r 'ิลหำิ'; -END utf8 utf8_general_ci utf8_unicode_ci +END utf8 utf8_general_ci utf8_unicode_ci # SHOW TRIGGERS| @@ -1981,7 +1981,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg2 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -1993,7 +1993,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest2| @@ -2010,7 +2010,7 @@ INSERT INTO log VALUES(@@character_set_client); SET @a1 = 'ั‚ะตะบัั‚'; SET @a2 = 'ั‚ะตะบัั‚'; SET @a3 = 'ั‚ะตะบัั‚'; -END BEFORE NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END BEFORE # root@localhost utf8 utf8_general_ci utf8_unicode_ci trg4 INSERT t1 BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); @@ -2022,13 +2022,13 @@ INSERT INTO log VALUES(@@character_set_client); SET @b1 = 'ั‚ะตะบัั‚'; SET @b2 = 'ั‚ะตะบัั‚'; SET @b3 = 'ั‚ะตะบัั‚'; -END AFTER NULL root@localhost utf8 utf8_general_ci utf8_unicode_ci +END AFTER # root@localhost utf8 utf8_general_ci utf8_unicode_ci use mysqltest1| SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg1'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg1 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg1 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -2043,7 +2043,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg2'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest1 trg2 INSERT def mysqltest1 t1 0 NULL BEGIN +def mysqltest1 trg2 INSERT def mysqltest1 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -2058,7 +2058,7 @@ END ROW AFTER NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci utf SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg3'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg3 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg3 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10); INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); @@ -2073,7 +2073,7 @@ END ROW BEFORE NULL NULL OLD NEW CREATED root@localhost utf8 utf8_general_ci ut SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 'trg4'| TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mysqltest2 trg4 INSERT def mysqltest2 t1 0 NULL BEGIN +def mysqltest2 trg4 INSERT def mysqltest2 t1 1 NULL BEGIN DECLARE ะฟะตั€ะตะผ1 CHAR(10) CHARACTER SET utf8; INSERT INTO log VALUES(COLLATION(ะฟะตั€ะตะผ1)); INSERT INTO log VALUES(COLLATION('ั‚ะตะบัั‚')); diff --git a/mysql-test/r/features.result b/mysql-test/r/features.result index b6a3ffa11ad..c6d1a6b0bac 100644 --- a/mysql-test/r/features.result +++ b/mysql-test/r/features.result @@ -118,7 +118,7 @@ select @a; 1 SHOW TRIGGERS IN test like 't1'; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg INSERT t1 set @a:=1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg INSERT t1 set @a:=1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci drop trigger trg; drop table t1; show status like "%trigger%"; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index c7a4edba65a..8be595a55f1 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -964,34 +964,34 @@ trg1 INSERT t1 begin if new.j > 10 then set new.j := 10; end if; -end BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +end BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci trg2 UPDATE t1 begin if old.i % 2 = 0 then set new.j := -1; end if; -end BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +end BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci trg3 UPDATE t1 begin if new.j = -1 then set @fired:= "Yes"; end if; -end AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +end AFTER # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci select * from information_schema.triggers where trigger_schema in ('mysql', 'information_schema', 'test', 'mysqltest'); TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def test trg1 INSERT def test t1 0 NULL begin +def test trg1 INSERT def test t1 1 NULL begin if new.j > 10 then set new.j := 10; end if; -end ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci -def test trg2 UPDATE def test t1 0 NULL begin +end ROW BEFORE NULL NULL OLD NEW # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def test trg2 UPDATE def test t1 1 NULL begin if old.i % 2 = 0 then set new.j := -1; end if; -end ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci -def test trg3 UPDATE def test t1 0 NULL begin +end ROW BEFORE NULL NULL OLD NEW # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def test trg3 UPDATE def test t1 1 NULL begin if new.j = -1 then set @fired:= "Yes"; end if; -end ROW AFTER NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +end ROW AFTER NULL NULL OLD NEW # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci drop trigger trg1; drop trigger trg2; drop trigger trg3; @@ -1406,7 +1406,7 @@ trigger_name t1_ai show triggers from mysqltest; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -t1_ai INSERT t1 set @a = new.a + new.b + new.c AFTER NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +t1_ai INSERT t1 set @a = new.a + new.b + new.c AFTER # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connect con27629,localhost,mysqltest_1,,mysqltest; show columns from t1; Field Type Null Key Default Extra diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 93b16896380..7f34d0a9217 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2289,8 +2289,8 @@ CREATE TABLE t2(a int); CREATE TABLE t3(a int) ENGINE = MERGE UNION(t1, t2); CREATE TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo(); SHOW CREATE TRIGGER tr1; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -tr1 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo() latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +tr1 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo() latin1 latin1_swedish_ci latin1_swedish_ci # DROP TRIGGER tr1; DROP TABLE t1, t2, t3; # diff --git a/mysql-test/r/mysql_comments.result b/mysql-test/r/mysql_comments.result index 4865c7a7af0..9ba8dff3d55 100644 --- a/mysql-test/r/mysql_comments.result +++ b/mysql-test/r/mysql_comments.result @@ -27,10 +27,10 @@ Procedure sql_mode Create Procedure character_set_client collation_connection Da foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n\n\n\n\n \n\n \n values ("foo", 42) latin1 latin1_swedish_ci latin1_swedish_ci Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n \n declare b int;\n declare c float;\n\n \n \n\n \nend latin1 latin1_swedish_ci latin1_swedish_ci -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n\n\n\n \n declare b int;\n declare c float;\n\n \n \n\n \n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci --TIME-- +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n\n\n\n \n declare b int;\n declare c float;\n\n \n \n\n \n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci --TIME-- id data trig 12 "Pass 2 : --enable-comments" @@ -54,10 +54,10 @@ Procedure sql_mode Create Procedure character_set_client collation_connection Da foosp CREATE DEFINER=`root`@`localhost` PROCEDURE `foosp`()\ninsert into test.t1\n## These comments are part of the procedure body, and should be kept.\n# Comment 2a\n-- Comment 2b\n/* Comment 2c */\n -- empty line below\n\n -- empty line above\n values ("foo", 42) # comment 3, still part of the body latin1 latin1_swedish_ci latin1_swedish_ci Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation nicesp CREATE DEFINER=`root`@`localhost` PROCEDURE `nicesp`(a int)\nbegin\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\nend latin1 latin1_swedish_ci latin1_swedish_ci -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation -t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n# comment 1a\n-- comment 1b\n/*\n comment 1c\n*/\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +t1_empty CREATE DEFINER=`root`@`localhost` trigger t1_empty after delete on t1\nfor each row\nbegin\nend latin1 latin1_swedish_ci latin1_swedish_ci --TIME-- +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +t1_bi CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1\nfor each row\nbegin\n# comment 1a\n-- comment 1b\n/*\n comment 1c\n*/\n -- declare some variables here\n declare b int;\n declare c float;\n\n -- do more stuff here\n -- commented nicely and so on\n\n -- famous last words ...\n set NEW.data := 12;\nend latin1 latin1_swedish_ci latin1_swedish_ci --TIME-- id data trig 12 set global sql_mode=default; diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 8894616fbb3..ff9cc5d5c81 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -241,15 +241,15 @@ CREATE TABLE t1 (a INT) engine=myisam; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA="#mysql50#a@b" ORDER BY trigger_name; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def #mysql50#a@b tr1 INSERT def #mysql50#a@b #mysql50#c@d 0 NULL SET NEW.a = 10 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci -def #mysql50#a@b tr2 INSERT def #mysql50#a@b t1 0 NULL SET NEW.a = 100 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def #mysql50#a@b tr1 INSERT def #mysql50#a@b #mysql50#c@d 1 NULL SET NEW.a = 10 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def #mysql50#a@b tr2 INSERT def #mysql50#a@b t1 1 NULL SET NEW.a = 100 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci mysqlcheck --fix-db-names --fix-table-names --all-databases USE `a@b`; SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA="a@b" ORDER BY trigger_name; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def a@b tr1 INSERT def a@b c@d 0 NULL SET NEW.a = 10 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost utf8 utf8_general_ci latin1_swedish_ci -def a@b tr2 INSERT def a@b t1 0 NULL SET NEW.a = 100 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost utf8 utf8_general_ci latin1_swedish_ci +def a@b tr1 INSERT def a@b c@d 1 NULL SET NEW.a = 10 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost utf8 utf8_general_ci latin1_swedish_ci +def a@b tr2 INSERT def a@b t1 1 NULL SET NEW.a = 100 * NEW.a ROW BEFORE NULL NULL OLD NEW NULL root@localhost utf8 utf8_general_ci latin1_swedish_ci INSERT INTO `c@d` VALUES (2), (1); SELECT * FROM `c@d`; a diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 98594973467..04612e02b7f 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -2717,7 +2717,7 @@ a2 SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation testref INSERT test1 BEGIN -INSERT INTO test2 SET a2 = NEW.a1; END BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +INSERT INTO test2 SET a2 = NEW.a1; END BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci SELECT * FROM `test1`; a1 1 @@ -4558,7 +4558,7 @@ CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT "Meow"; SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr1 UPDATE t1 SET @f1 = 1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation test ev1 root@localhost SYSTEM ONE TIME 2030-01-01 00:00:00 NULL NULL NULL NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci @@ -4577,7 +4577,7 @@ DROP PROCEDURE pr1; reload table; this should restore table and trigger SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr1 UPDATE t1 SET @f1 = 1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation SELECT name,body FROM mysql.proc WHERE NAME = 'pr1'; @@ -4586,7 +4586,7 @@ name body reload db; this should restore routines and events SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr1 UPDATE t1 SET @f1 = 1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW EVENTS; Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation test ev1 root@localhost SYSTEM ONE TIME 2030-01-01 00:00:00 NULL NULL NULL NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci @@ -4812,7 +4812,7 @@ CREATE VIEW v2 AS SELECT * FROM t2; - + - + - + - + - + - + + + + + + + + + + + + + + + + + + +DROP TABLE t1; +# +# Test 20. Check that the statement CHECK TABLE FOR UPGRADE outputs +# the warnings for triggers created by a server without support for wl3253. +# +CREATE TABLE t1 (a INT); +FLUSH TABLE t1; +CHECK TABLE t1 FOR UPGRADE; +Table Op Msg_type Msg_text +test.t1 check status OK +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 NULL NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr1_ai INSERT t1 SET @a:=2 AFTER NULL NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'test'; +TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION +def test tr1_bi INSERT def test t1 1 NULL SET @a:=1 ROW BEFORE NULL NULL OLD NEW NULL NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def test tr1_ai INSERT def test t1 1 NULL SET @a:=2 ROW AFTER NULL NULL OLD NEW NULL NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +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 NULL +SHOW CREATE TRIGGER tr1_ai; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created +tr1_ai NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` TRIGGER tr1_ai AFTER INSERT ON t1 FOR EACH ROW SET @a:=2 latin1 latin1_swedish_ci latin1_swedish_ci NULL +DROP TABLE t1; +SET binlog_format=@binlog_format_saved; +# End of tests. +# diff --git a/mysql-test/suite/binlog/r/binlog_trigger.result b/mysql-test/suite/binlog/r/binlog_trigger.result new file mode 100644 index 00000000000..48ec1dd629e --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_trigger.result @@ -0,0 +1,24 @@ +# +# WL#3253: multiple triggers per table +# +# Testing that the FOLLOWS and PRECEDES clauses get logged +CREATE TABLE t1 (a INT, b INT); +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); +CREATE TRIGGER tr4_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi INSERT INTO t2 (a) VALUES (NEW.a + 200); +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW precedes tr4_bi INSERT INTO t2 (a) VALUES (NEW.a + 400); +DROP TABLE t1; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr4_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi INSERT INTO t2 (a) VALUES (NEW.a + 200) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW precedes tr4_bi INSERT INTO t2 (a) VALUES (NEW.a + 400) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ diff --git a/mysql-test/suite/binlog/t/binlog_trigger.test b/mysql-test/suite/binlog/t/binlog_trigger.test new file mode 100644 index 00000000000..4ad5d16a1f8 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_trigger.test @@ -0,0 +1,23 @@ +--source include/not_embedded.inc +--source include/have_binlog_format_statement.inc + +--disable_query_log +reset master; # get rid of previous tests binlog +--enable_query_log + +--echo # +--echo # WL#3253: multiple triggers per table +--echo # + +--echo # Testing that the FOLLOWS and PRECEDES clauses get logged + +CREATE TABLE t1 (a INT, b INT); +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); +CREATE TRIGGER tr4_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi INSERT INTO t2 (a) VALUES (NEW.a + 200); +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW precedes tr4_bi INSERT INTO t2 (a) VALUES (NEW.a + 400); +DROP TABLE t1; + + +--let $binlog_file = LAST +source include/show_binlog_events.inc; diff --git a/mysql-test/suite/funcs_1/datadict/is_triggers.inc b/mysql-test/suite/funcs_1/datadict/is_triggers.inc index cb2c461dd39..82cf6f8e21f 100644 --- a/mysql-test/suite/funcs_1/datadict/is_triggers.inc +++ b/mysql-test/suite/funcs_1/datadict/is_triggers.inc @@ -81,6 +81,7 @@ eval SHOW COLUMNS FROM information_schema.$is_table; # information_schema.tables is in is_columns_is.test. # Show that several columns are always NULL. +--replace_column 17 # SELECT * FROM information_schema.triggers WHERE trigger_catalog IS NOT NULL OR event_object_catalog IS NOT NULL OR action_condition IS NOT NULL OR action_reference_old_table IS NOT NULL @@ -134,21 +135,27 @@ ON db_datadict.t1 FOR EACH ROW SET @test_before = 2, new.f1 = @test_before; GRANT ALL ON db_datadict.t1 TO 'testuser2'@'localhost'; REVOKE TRIGGER ON db_datadict.t1 FROM 'testuser2'@'localhost'; GRANT SELECT ON db_datadict.t1 TO 'testuser3'@'localhost'; +--replace_column 17 # eval $my_select; +--replace_column 6 # eval $my_show; --replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK connect (testuser2, localhost, testuser2, , db_datadict); SHOW GRANTS FOR 'testuser2'@'localhost'; --echo # No TRIGGER Privilege --> no result for query +--replace_column 17 # eval $my_select; +--replace_column 6 # eval $my_show; --replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK connect (testuser3, localhost, testuser3, , test); SHOW GRANTS FOR 'testuser3'@'localhost'; --echo # TRIGGER Privilege + SELECT Privilege on t1 --> result for query +--replace_column 17 # eval $my_select; +--replace_column 6 # eval $my_show; --replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK @@ -158,7 +165,9 @@ SHOW GRANTS FOR 'testuser4'@'localhost'; --disable_abort_on_error SELECT * FROM db_datadict.t1; DESC db_datadict.t1; +--replace_column 17 # eval $my_select; +--replace_column 6 # eval $my_show; connection default; @@ -166,7 +175,9 @@ disconnect testuser1; disconnect testuser2; disconnect testuser3; disconnect testuser4; +--replace_column 17 # eval $my_select; +--replace_column 6 # eval $my_show; DROP USER 'testuser1'@'localhost'; DROP USER 'testuser2'@'localhost'; diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result index e44e17c6392..4e4716fd873 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result @@ -486,8 +486,8 @@ create trigger trg1_4 before UPDATE on t1 for each row set new.f1 = 'trig 1_4-yes'; show triggers; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci -trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection no_privs; select current_user; current_user diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_0407.result b/mysql-test/suite/funcs_1/r/innodb_trig_0407.result index d450096176d..81ead0c9346 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_0407.result @@ -332,11 +332,10 @@ Create trigger trg5_1 BEFORE INSERT on tb3 for each row set new.f122='Trigger1 3.5.7.5/6'; Create trigger trg5_2 BEFORE INSERT on tb3 for each row set new.f122='Trigger2 3.5.7.5'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.5/6','Insert 3.5.7.5'); Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 -Test 3.5.7.5/6 Trigger1 3.5.7.5/6 +Test 3.5.7.5/6 Trigger2 3.5.7.5 update tb3 set f122='Update 3.5.7.6' where f121= 'Test 3.5.7.5/6'; Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 @@ -352,7 +351,6 @@ Create trigger trg6_1 AFTER INSERT on tb3 for each row set @test_var='Trigger1 3.5.7.7/8'; Create trigger trg6_2 AFTER INSERT on tb3 for each row set @test_var='Trigger2 3.5.7.7'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.7 @@ -362,14 +360,14 @@ f121 f122 Test 3.5.7.7/8 Insert 3.5.7.7 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 update tb3 set f122='Update 3.5.7.8' where f121= 'Test 3.5.7.7/8'; Select f121,f122 from tb3 where f121='Test 3.5.7.7/8'; f121 f122 Test 3.5.7.7/8 Update 3.5.7.8 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 drop trigger trg6_1; drop trigger trg6_2; delete from tb3 where f121='Test 3.5.7.7/8'; @@ -380,7 +378,6 @@ Create trigger trg7_1 BEFORE UPDATE on tb3 for each row set new.f122='Trigger1 3.5.7.9/10'; Create trigger trg7_2 BEFORE UPDATE on tb3 for each row set new.f122='Trigger2 3.5.7.9'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.9/10','Insert 3.5.7.9'); Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 @@ -388,7 +385,7 @@ Test 3.5.7.9/10 Insert 3.5.7.9 update tb3 set f122='update 3.5.7.10' where f121='Test 3.5.7.9/10'; Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 -Test 3.5.7.9/10 Trigger1 3.5.7.9/10 +Test 3.5.7.9/10 Trigger2 3.5.7.9 drop trigger trg7_1; drop trigger trg7_2; delete from tb3 where f121='Test 3.5.7.9/10'; @@ -400,7 +397,6 @@ Create trigger trg8_1 AFTER UPDATE on tb3 for each row set @test_var='Trigger 3.5.7.11/12'; Create trigger trg8_2 AFTER UPDATE on tb3 for each row set @test_var='Trigger2 3.5.7.11'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.11 @@ -417,7 +413,7 @@ f121 f122 Test 3.5.7.11/12 update 3.5.7.12 select @test_var; @test_var -Trigger 3.5.7.11/12 +Trigger2 3.5.7.11 delete from tb3 where f121='Test 3.5.7.11/12'; drop trigger trg8_1; drop trigger trg8_2; @@ -430,7 +426,6 @@ Create trigger trg9_1 BEFORE DELETE on tb3 for each row set @test_var=@test_var+1; Create trigger trg9_2 BEFORE DELETE on tb3 for each row set @test_var=@test_var+10; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var 1 @@ -446,11 +441,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.13/14'; f121 f122 select @test_var; @test_var -2 +12 delete from tb3 where f121='Test 3.5.7.13/14'; select @test_var; @test_var -2 +12 drop trigger trg9_1; drop trigger trg9_2; delete from tb3 where f121='Test 3.5.7.13/14'; @@ -462,7 +457,6 @@ Create trigger trg_3_406010_1 AFTER DELETE on tb3 for each row set @test_var=@test_var+5; Create trigger trg_3_406010_2 AFTER DELETE on tb3 for each row set @test_var=@test_var+50; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Create trigger trg_3_406010_1 AFTER INSERT on tb3 for each row set @test_var=@test_var+1; ERROR HY000: Trigger already exists @@ -481,11 +475,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.15/16'; f121 f122 select @test_var; @test_var -6 +56 delete from tb3 where f121='Test 3.5.7.15/16'; select @test_var; @test_var -6 +56 drop trigger trg_3_406010_1; drop trigger trg_3_406010_2; delete from tb3 where f121='Test 3.5.7.15/16'; diff --git a/mysql-test/suite/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result index d21cefa7c57..0f35e66d6a6 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is.result @@ -417,7 +417,7 @@ def information_schema TRIGGERS ACTION_STATEMENT 10 NO longtext 4294967295 4294 def information_schema TRIGGERS ACTION_TIMING 12 NO varchar 6 18 NULL NULL NULL utf8 utf8_general_ci varchar(6) select def information_schema TRIGGERS CHARACTER_SET_CLIENT 20 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) select def information_schema TRIGGERS COLLATION_CONNECTION 21 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) select -def information_schema TRIGGERS CREATED 17 NULL YES datetime NULL NULL NULL NULL 0 NULL NULL datetime select +def information_schema TRIGGERS CREATED 17 NULL YES datetime NULL NULL NULL NULL 2 NULL NULL datetime(2) select def information_schema TRIGGERS DATABASE_COLLATION 22 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) select def information_schema TRIGGERS DEFINER 19 NO varchar 189 567 NULL NULL NULL utf8 utf8_general_ci varchar(189) select def information_schema TRIGGERS EVENT_MANIPULATION 4 NO varchar 6 18 NULL NULL NULL utf8 utf8_general_ci varchar(6) select @@ -950,7 +950,7 @@ NULL information_schema TRIGGERS ACTION_ORDER bigint NULL NULL NULL NULL bigint( 3.0000 information_schema TRIGGERS ACTION_REFERENCE_NEW_TABLE varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema TRIGGERS ACTION_REFERENCE_OLD_ROW varchar 3 9 utf8 utf8_general_ci varchar(3) 3.0000 information_schema TRIGGERS ACTION_REFERENCE_NEW_ROW varchar 3 9 utf8 utf8_general_ci varchar(3) -NULL information_schema TRIGGERS CREATED datetime NULL NULL NULL NULL datetime +NULL information_schema TRIGGERS CREATED datetime NULL NULL NULL NULL datetime(2) 3.0000 information_schema TRIGGERS SQL_MODE varchar 8192 24576 utf8 utf8_general_ci varchar(8192) 3.0000 information_schema TRIGGERS DEFINER varchar 189 567 utf8 utf8_general_ci varchar(189) 3.0000 information_schema TRIGGERS CHARACTER_SET_CLIENT varchar 32 96 utf8 utf8_general_ci varchar(32) diff --git a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result index b740a04f015..69c5d79b541 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result @@ -417,7 +417,7 @@ def information_schema TRIGGERS ACTION_STATEMENT 10 NO longtext 4294967295 4294 def information_schema TRIGGERS ACTION_TIMING 12 NO varchar 6 18 NULL NULL NULL utf8 utf8_general_ci varchar(6) def information_schema TRIGGERS CHARACTER_SET_CLIENT 20 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) def information_schema TRIGGERS COLLATION_CONNECTION 21 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) -def information_schema TRIGGERS CREATED 17 NULL YES datetime NULL NULL NULL NULL 0 NULL NULL datetime +def information_schema TRIGGERS CREATED 17 NULL YES datetime NULL NULL NULL NULL 2 NULL NULL datetime(2) def information_schema TRIGGERS DATABASE_COLLATION 22 NO varchar 32 96 NULL NULL NULL utf8 utf8_general_ci varchar(32) def information_schema TRIGGERS DEFINER 19 NO varchar 189 567 NULL NULL NULL utf8 utf8_general_ci varchar(189) def information_schema TRIGGERS EVENT_MANIPULATION 4 NO varchar 6 18 NULL NULL NULL utf8 utf8_general_ci varchar(6) @@ -950,7 +950,7 @@ NULL information_schema TRIGGERS ACTION_ORDER bigint NULL NULL NULL NULL bigint( 3.0000 information_schema TRIGGERS ACTION_REFERENCE_NEW_TABLE varchar 64 192 utf8 utf8_general_ci varchar(64) 3.0000 information_schema TRIGGERS ACTION_REFERENCE_OLD_ROW varchar 3 9 utf8 utf8_general_ci varchar(3) 3.0000 information_schema TRIGGERS ACTION_REFERENCE_NEW_ROW varchar 3 9 utf8 utf8_general_ci varchar(3) -NULL information_schema TRIGGERS CREATED datetime NULL NULL NULL NULL datetime +NULL information_schema TRIGGERS CREATED datetime NULL NULL NULL NULL datetime(2) 3.0000 information_schema TRIGGERS SQL_MODE varchar 8192 24576 utf8 utf8_general_ci varchar(8192) 3.0000 information_schema TRIGGERS DEFINER varchar 189 567 utf8 utf8_general_ci varchar(189) 3.0000 information_schema TRIGGERS CHARACTER_SET_CLIENT varchar 32 96 utf8 utf8_general_ci varchar(32) diff --git a/mysql-test/suite/funcs_1/r/is_triggers.result b/mysql-test/suite/funcs_1/r/is_triggers.result index ac6372b1d84..d20eeb9a319 100644 --- a/mysql-test/suite/funcs_1/r/is_triggers.result +++ b/mysql-test/suite/funcs_1/r/is_triggers.result @@ -45,7 +45,7 @@ ACTION_REFERENCE_OLD_TABLE varchar(64) YES NULL ACTION_REFERENCE_NEW_TABLE varchar(64) YES NULL ACTION_REFERENCE_OLD_ROW varchar(3) NO ACTION_REFERENCE_NEW_ROW varchar(3) NO -CREATED datetime YES NULL +CREATED datetime(2) YES NULL SQL_MODE varchar(8192) NO DEFINER varchar(189) NO CHARACTER_SET_CLIENT varchar(32) NO @@ -70,7 +70,7 @@ TRIGGERS CREATE TEMPORARY TABLE `TRIGGERS` ( `ACTION_REFERENCE_NEW_TABLE` varchar(64) DEFAULT NULL, `ACTION_REFERENCE_OLD_ROW` varchar(3) NOT NULL DEFAULT '', `ACTION_REFERENCE_NEW_ROW` varchar(3) NOT NULL DEFAULT '', - `CREATED` datetime DEFAULT NULL, + `CREATED` datetime(2) DEFAULT NULL, `SQL_MODE` varchar(8192) NOT NULL DEFAULT '', `DEFINER` varchar(189) NOT NULL DEFAULT '', `CHARACTER_SET_CLIENT` varchar(32) NOT NULL DEFAULT '', @@ -95,7 +95,7 @@ ACTION_REFERENCE_OLD_TABLE varchar(64) YES NULL ACTION_REFERENCE_NEW_TABLE varchar(64) YES NULL ACTION_REFERENCE_OLD_ROW varchar(3) NO ACTION_REFERENCE_NEW_ROW varchar(3) NO -CREATED datetime YES NULL +CREATED datetime(2) YES NULL SQL_MODE varchar(8192) NO DEFINER varchar(189) NO CHARACTER_SET_CLIENT varchar(32) NO @@ -106,8 +106,8 @@ WHERE trigger_catalog IS NOT NULL OR event_object_catalog IS NOT NULL OR action_condition IS NOT NULL OR action_reference_old_table IS NOT NULL OR action_reference_new_table IS NOT NULL; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def mtr gs_insert INSERT def mtr global_suppressions 0 NULL BEGIN DECLARE dummy INT; SELECT "" REGEXP NEW.pattern INTO dummy; END ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci -def mtr ts_insert INSERT def mtr test_suppressions 0 NULL BEGIN DECLARE dummy INT; SELECT "" REGEXP NEW.pattern INTO dummy; END ROW BEFORE NULL NULL OLD NEW NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def mtr gs_insert INSERT def mtr global_suppressions 1 NULL BEGIN DECLARE dummy INT; SELECT "" REGEXP NEW.pattern INTO dummy; END ROW BEFORE NULL NULL OLD NEW # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def mtr ts_insert INSERT def mtr test_suppressions 1 NULL BEGIN DECLARE dummy INT; SELECT "" REGEXP NEW.pattern INTO dummy; END ROW BEFORE NULL NULL OLD NEW # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci ################################################################################## # Testcase 3.2.18.2 + 3.2.18.3: INFORMATION_SCHEMA.TRIGGERS accessible information ################################################################################## @@ -136,10 +136,10 @@ GRANT SELECT ON db_datadict.t1 TO 'testuser3'@'localhost'; SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def db_datadict trg1 INSERT def db_datadict t1 0 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def db_datadict trg1 INSERT def db_datadict t1 1 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW TRIGGERS FROM db_datadict; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci connect testuser2, localhost, testuser2, , db_datadict; SHOW GRANTS FOR 'testuser2'@'localhost'; Grants for testuser2@localhost @@ -160,10 +160,10 @@ GRANT SELECT ON `db_datadict`.`t1` TO 'testuser3'@'localhost' SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def db_datadict trg1 INSERT def db_datadict t1 0 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def db_datadict trg1 INSERT def db_datadict t1 1 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW TRIGGERS FROM db_datadict; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci connect testuser4, localhost, testuser4, , test; SHOW GRANTS FOR 'testuser4'@'localhost'; Grants for testuser4@localhost @@ -176,10 +176,10 @@ ERROR 42000: SELECT command denied to user 'testuser4'@'localhost' for table 't1 SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def db_datadict trg1 INSERT def db_datadict t1 0 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def db_datadict trg1 INSERT def db_datadict t1 1 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW TRIGGERS FROM db_datadict; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection default; disconnect testuser1; disconnect testuser2; @@ -188,10 +188,10 @@ disconnect testuser4; SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED SQL_MODE DEFINER CHARACTER_SET_CLIENT COLLATION_CONNECTION DATABASE_COLLATION -def db_datadict trg1 INSERT def db_datadict t1 0 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +def db_datadict trg1 INSERT def db_datadict t1 1 NULL SET @test_before = 2, new.f1 = @test_before ROW BEFORE NULL NULL OLD NEW # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci SHOW TRIGGERS FROM db_datadict; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE NULL testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @test_before = 2, new.f1 = @test_before BEFORE # testuser1@localhost latin1 latin1_swedish_ci latin1_swedish_ci DROP USER 'testuser1'@'localhost'; DROP USER 'testuser2'@'localhost'; DROP USER 'testuser3'@'localhost'; diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03e.result b/mysql-test/suite/funcs_1/r/memory_trig_03e.result index 768e1577177..f9e8fc05088 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03e.result @@ -487,8 +487,8 @@ create trigger trg1_4 before UPDATE on t1 for each row set new.f1 = 'trig 1_4-yes'; show triggers; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci -trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection no_privs; select current_user; current_user diff --git a/mysql-test/suite/funcs_1/r/memory_trig_0407.result b/mysql-test/suite/funcs_1/r/memory_trig_0407.result index 9b23271958a..72a7cb4f01d 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_0407.result @@ -332,11 +332,10 @@ Create trigger trg5_1 BEFORE INSERT on tb3 for each row set new.f122='Trigger1 3.5.7.5/6'; Create trigger trg5_2 BEFORE INSERT on tb3 for each row set new.f122='Trigger2 3.5.7.5'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.5/6','Insert 3.5.7.5'); Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 -Test 3.5.7.5/6 Trigger1 3.5.7.5/6 +Test 3.5.7.5/6 Trigger2 3.5.7.5 update tb3 set f122='Update 3.5.7.6' where f121= 'Test 3.5.7.5/6'; Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 @@ -352,7 +351,6 @@ Create trigger trg6_1 AFTER INSERT on tb3 for each row set @test_var='Trigger1 3.5.7.7/8'; Create trigger trg6_2 AFTER INSERT on tb3 for each row set @test_var='Trigger2 3.5.7.7'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.7 @@ -362,14 +360,14 @@ f121 f122 Test 3.5.7.7/8 Insert 3.5.7.7 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 update tb3 set f122='Update 3.5.7.8' where f121= 'Test 3.5.7.7/8'; Select f121,f122 from tb3 where f121='Test 3.5.7.7/8'; f121 f122 Test 3.5.7.7/8 Update 3.5.7.8 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 drop trigger trg6_1; drop trigger trg6_2; delete from tb3 where f121='Test 3.5.7.7/8'; @@ -380,7 +378,6 @@ Create trigger trg7_1 BEFORE UPDATE on tb3 for each row set new.f122='Trigger1 3.5.7.9/10'; Create trigger trg7_2 BEFORE UPDATE on tb3 for each row set new.f122='Trigger2 3.5.7.9'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.9/10','Insert 3.5.7.9'); Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 @@ -388,7 +385,7 @@ Test 3.5.7.9/10 Insert 3.5.7.9 update tb3 set f122='update 3.5.7.10' where f121='Test 3.5.7.9/10'; Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 -Test 3.5.7.9/10 Trigger1 3.5.7.9/10 +Test 3.5.7.9/10 Trigger2 3.5.7.9 drop trigger trg7_1; drop trigger trg7_2; delete from tb3 where f121='Test 3.5.7.9/10'; @@ -400,7 +397,6 @@ Create trigger trg8_1 AFTER UPDATE on tb3 for each row set @test_var='Trigger 3.5.7.11/12'; Create trigger trg8_2 AFTER UPDATE on tb3 for each row set @test_var='Trigger2 3.5.7.11'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.11 @@ -417,7 +413,7 @@ f121 f122 Test 3.5.7.11/12 update 3.5.7.12 select @test_var; @test_var -Trigger 3.5.7.11/12 +Trigger2 3.5.7.11 delete from tb3 where f121='Test 3.5.7.11/12'; drop trigger trg8_1; drop trigger trg8_2; @@ -430,7 +426,6 @@ Create trigger trg9_1 BEFORE DELETE on tb3 for each row set @test_var=@test_var+1; Create trigger trg9_2 BEFORE DELETE on tb3 for each row set @test_var=@test_var+10; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var 1 @@ -446,11 +441,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.13/14'; f121 f122 select @test_var; @test_var -2 +12 delete from tb3 where f121='Test 3.5.7.13/14'; select @test_var; @test_var -2 +12 drop trigger trg9_1; drop trigger trg9_2; delete from tb3 where f121='Test 3.5.7.13/14'; @@ -462,7 +457,6 @@ Create trigger trg_3_406010_1 AFTER DELETE on tb3 for each row set @test_var=@test_var+5; Create trigger trg_3_406010_2 AFTER DELETE on tb3 for each row set @test_var=@test_var+50; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Create trigger trg_3_406010_1 AFTER INSERT on tb3 for each row set @test_var=@test_var+1; ERROR HY000: Trigger already exists @@ -481,11 +475,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.15/16'; f121 f122 select @test_var; @test_var -6 +56 delete from tb3 where f121='Test 3.5.7.15/16'; select @test_var; @test_var -6 +56 drop trigger trg_3_406010_1; drop trigger trg_3_406010_2; delete from tb3 where f121='Test 3.5.7.15/16'; diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result index 420bdf2dc2d..d1ab5674cb4 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result @@ -487,8 +487,8 @@ create trigger trg1_4 before UPDATE on t1 for each row set new.f1 = 'trig 1_4-yes'; show triggers; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci -trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_3 INSERT t1 set new.f1 = 'trig 1_3-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1_4 UPDATE t1 set new.f1 = 'trig 1_4-yes' BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION test_yesprivs@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection no_privs; select current_user; current_user diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_0407.result b/mysql-test/suite/funcs_1/r/myisam_trig_0407.result index 9b23271958a..72a7cb4f01d 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_0407.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_0407.result @@ -332,11 +332,10 @@ Create trigger trg5_1 BEFORE INSERT on tb3 for each row set new.f122='Trigger1 3.5.7.5/6'; Create trigger trg5_2 BEFORE INSERT on tb3 for each row set new.f122='Trigger2 3.5.7.5'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.5/6','Insert 3.5.7.5'); Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 -Test 3.5.7.5/6 Trigger1 3.5.7.5/6 +Test 3.5.7.5/6 Trigger2 3.5.7.5 update tb3 set f122='Update 3.5.7.6' where f121= 'Test 3.5.7.5/6'; Select f121,f122 from tb3 where f121='Test 3.5.7.5/6'; f121 f122 @@ -352,7 +351,6 @@ Create trigger trg6_1 AFTER INSERT on tb3 for each row set @test_var='Trigger1 3.5.7.7/8'; Create trigger trg6_2 AFTER INSERT on tb3 for each row set @test_var='Trigger2 3.5.7.7'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.7 @@ -362,14 +360,14 @@ f121 f122 Test 3.5.7.7/8 Insert 3.5.7.7 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 update tb3 set f122='Update 3.5.7.8' where f121= 'Test 3.5.7.7/8'; Select f121,f122 from tb3 where f121='Test 3.5.7.7/8'; f121 f122 Test 3.5.7.7/8 Update 3.5.7.8 select @test_var; @test_var -Trigger1 3.5.7.7/8 +Trigger2 3.5.7.7 drop trigger trg6_1; drop trigger trg6_2; delete from tb3 where f121='Test 3.5.7.7/8'; @@ -380,7 +378,6 @@ Create trigger trg7_1 BEFORE UPDATE on tb3 for each row set new.f122='Trigger1 3.5.7.9/10'; Create trigger trg7_2 BEFORE UPDATE on tb3 for each row set new.f122='Trigger2 3.5.7.9'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Insert into tb3 (f121,f122) values ('Test 3.5.7.9/10','Insert 3.5.7.9'); Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 @@ -388,7 +385,7 @@ Test 3.5.7.9/10 Insert 3.5.7.9 update tb3 set f122='update 3.5.7.10' where f121='Test 3.5.7.9/10'; Select f121,f122 from tb3 where f121='Test 3.5.7.9/10'; f121 f122 -Test 3.5.7.9/10 Trigger1 3.5.7.9/10 +Test 3.5.7.9/10 Trigger2 3.5.7.9 drop trigger trg7_1; drop trigger trg7_2; delete from tb3 where f121='Test 3.5.7.9/10'; @@ -400,7 +397,6 @@ Create trigger trg8_1 AFTER UPDATE on tb3 for each row set @test_var='Trigger 3.5.7.11/12'; Create trigger trg8_2 AFTER UPDATE on tb3 for each row set @test_var='Trigger2 3.5.7.11'; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var Before trig 3.5.7.11 @@ -417,7 +413,7 @@ f121 f122 Test 3.5.7.11/12 update 3.5.7.12 select @test_var; @test_var -Trigger 3.5.7.11/12 +Trigger2 3.5.7.11 delete from tb3 where f121='Test 3.5.7.11/12'; drop trigger trg8_1; drop trigger trg8_2; @@ -430,7 +426,6 @@ Create trigger trg9_1 BEFORE DELETE on tb3 for each row set @test_var=@test_var+1; Create trigger trg9_2 BEFORE DELETE on tb3 for each row set @test_var=@test_var+10; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' select @test_var; @test_var 1 @@ -446,11 +441,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.13/14'; f121 f122 select @test_var; @test_var -2 +12 delete from tb3 where f121='Test 3.5.7.13/14'; select @test_var; @test_var -2 +12 drop trigger trg9_1; drop trigger trg9_2; delete from tb3 where f121='Test 3.5.7.13/14'; @@ -462,7 +457,6 @@ Create trigger trg_3_406010_1 AFTER DELETE on tb3 for each row set @test_var=@test_var+5; Create trigger trg_3_406010_2 AFTER DELETE on tb3 for each row set @test_var=@test_var+50; -ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table' Create trigger trg_3_406010_1 AFTER INSERT on tb3 for each row set @test_var=@test_var+1; ERROR HY000: Trigger already exists @@ -481,11 +475,11 @@ Select f121,f122 from tb3 where f121='Test 3.5.7.15/16'; f121 f122 select @test_var; @test_var -6 +56 delete from tb3 where f121='Test 3.5.7.15/16'; select @test_var; @test_var -6 +56 drop trigger trg_3_406010_1; drop trigger trg_3_406010_2; delete from tb3 where f121='Test 3.5.7.15/16'; diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc index 2bbcc5f88f0..e56a5972ce6 100644 --- a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc +++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc @@ -120,6 +120,7 @@ let $message= no trigger privilege on table level for create:; connection default; select current_user; +--replace_column 6 # show triggers; grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -128,6 +129,7 @@ let $message= trigger privilege on table level for create:; --source include/show_msg.inc connection yes_privs; select current_user; +--replace_column 6 # show triggers; create trigger trg1_2 before INSERT on t1 for each row set new.f1 = 'trig 1_2-yes'; diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc index eebdff5b588..f84474f1541 100644 --- a/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc +++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc @@ -84,6 +84,7 @@ let $message= trigger privilege on user level for create:; connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK); select current_user; use priv_db; +--replace_column 6 # show triggers; select * from information_schema.triggers; --error ER_TABLEACCESS_DENIED_ERROR diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc index 6258b040642..e2efa5774fa 100644 --- a/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc +++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc @@ -36,6 +36,7 @@ let $message= #### Testcase for trigger privilege on execution time ########; connection default; select current_user; +--replace_column 6 # show triggers; grant select, insert, update ,trigger on priv_db.t1 to test_yesprivs@localhost diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc index ca4b9e2a0a9..bd6bee9bcf2 100644 --- a/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc +++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc @@ -44,6 +44,7 @@ let $message= no trigger privilege on table level for create:; --source include/show_msg.inc connection default; select current_user; +--replace_column 6 # show triggers; grant select, insert, update on priv_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -68,6 +69,7 @@ let $message= no trigger privilege on table level for create:; connection default; select current_user; +--replace_column 6 # show triggers; show tables; insert into t1 (f1) values ('insert2-yes'); @@ -81,6 +83,7 @@ let $message= trigger privilege on table level for create:; --source include/show_msg.inc connection yes_privs; select current_user; +--replace_column 6 # show triggers; create trigger trg1_2 before INSERT on t1 for each row set new.f1 = 'trig 1_2-yes'; @@ -179,6 +182,7 @@ let $message= use table with trigger privilege and without...:; set new.f1 = 'trig 2_2-no'; create trigger trg1_4 before UPDATE on t1 for each row set new.f1 = 'trig 1_4-yes'; +--replace_column 6 # show triggers; connection no_privs; select current_user; diff --git a/mysql-test/suite/funcs_1/triggers/triggers_0407.inc b/mysql-test/suite/funcs_1/triggers/triggers_0407.inc index 907260a00f0..71471696761 100644 --- a/mysql-test/suite/funcs_1/triggers/triggers_0407.inc +++ b/mysql-test/suite/funcs_1/triggers/triggers_0407.inc @@ -420,16 +420,15 @@ let $message= Testcase 3.5.7.4:; --enable_warnings #Section 3.5.7.5 / 3.5.7.6 -# Test case: Ensure that it is not possible to create multiple BEFORE INSERT triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that it is possible to create multiple BEFORE INSERT +# triggers on the same table +# let $message= Testcase 3.5.7.5 / 3.5.7.6:; --source include/show_msg.inc Create trigger trg5_1 BEFORE INSERT on tb3 for each row set new.f122='Trigger1 3.5.7.5/6'; - --error ER_NOT_SUPPORTED_YET Create trigger trg5_2 BEFORE INSERT on tb3 for each row set new.f122='Trigger2 3.5.7.5'; @@ -441,16 +440,14 @@ let $message= Testcase 3.5.7.5 / 3.5.7.6:; #Cleanup --disable_warnings drop trigger trg5_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg5_2; delete from tb3 where f121='Test 3.5.7.5/6'; --enable_warnings #Section 3.5.7.7 / 3.5.7.8 -# Test case: Ensure that it is not possible to create multiple AFTER INSERT triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that it is possible to create multiple AFTER INSERT +# triggers on the same table let $message= Testcase 3.5.7.7 / 3.5.7.8:; --source include/show_msg.inc @@ -458,7 +455,6 @@ let $message= Testcase 3.5.7.7 / 3.5.7.8:; Create trigger trg6_1 AFTER INSERT on tb3 for each row set @test_var='Trigger1 3.5.7.7/8'; - --error ER_NOT_SUPPORTED_YET Create trigger trg6_2 AFTER INSERT on tb3 for each row set @test_var='Trigger2 3.5.7.7'; @@ -473,23 +469,20 @@ let $message= Testcase 3.5.7.7 / 3.5.7.8:; #Cleanup --disable_warnings drop trigger trg6_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg6_2; delete from tb3 where f121='Test 3.5.7.7/8'; --enable_warnings #Section 3.5.7.9 / 3.5.7.10 -# Test case: Ensure that it is not possible to create multiple BEFORE UPDATE triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that it is possible to create multiple BEFORE UPDATE +# triggers on the same table let $message= Testcase 3.5.7.9/10:; --source include/show_msg.inc Create trigger trg7_1 BEFORE UPDATE on tb3 for each row set new.f122='Trigger1 3.5.7.9/10'; - --error ER_NOT_SUPPORTED_YET Create trigger trg7_2 BEFORE UPDATE on tb3 for each row set new.f122='Trigger2 3.5.7.9'; @@ -501,14 +494,12 @@ let $message= Testcase 3.5.7.9/10:; #Cleanup --disable_warnings drop trigger trg7_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg7_2; delete from tb3 where f121='Test 3.5.7.9/10'; #Section 3.5.7.11 / 3.5.7.12 -# Test case: Ensure that it is not possible to create multiple AFTER UPDATE triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that it is possible to create multiple AFTER UPDATE +# triggers on the same table let $message= Testcase 3.5.7.11/12:; --source include/show_msg.inc @@ -516,11 +507,9 @@ let $message= Testcase 3.5.7.11/12:; Create trigger trg8_1 AFTER UPDATE on tb3 for each row set @test_var='Trigger 3.5.7.11/12'; - --error ER_NOT_SUPPORTED_YET Create trigger trg8_2 AFTER UPDATE on tb3 for each row set @test_var='Trigger2 3.5.7.11'; - select @test_var; Insert into tb3 (f121,f122) values ('Test 3.5.7.11/12','Insert 3.5.7.11/12'); select @test_var; @@ -533,14 +522,12 @@ let $message= Testcase 3.5.7.11/12:; #Cleanup --disable_warnings drop trigger trg8_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg8_2; delete from tb3 where f121='Test 3.5.7.11/12'; #Section 3.5.7.13 / 3.5.7.14 -# Test case: Ensure that it is not possible to create multiple BEFORE DELETE triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that it is possible to create multiple BEFORE DELETE +# triggers on the same table let $message= Testcase 3.5.7.13/14:; --source include/show_msg.inc @@ -548,7 +535,6 @@ let $message= Testcase 3.5.7.13/14:; Create trigger trg9_1 BEFORE DELETE on tb3 for each row set @test_var=@test_var+1; - --error ER_NOT_SUPPORTED_YET Create trigger trg9_2 BEFORE DELETE on tb3 for each row set @test_var=@test_var+10; @@ -565,14 +551,12 @@ let $message= Testcase 3.5.7.13/14:; #Cleanup --disable_warnings drop trigger trg9_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg9_2; delete from tb3 where f121='Test 3.5.7.13/14'; #Section 3.5.7.15 / 3.5.7.16 -# Test case: Ensure that it is not possible to create multiple AFTER DELETE triggers -# on the same table, even if the triggers have different names / different -# triggered actions. +# Test case: Ensure that possible to create multiple AFTER DELETE triggers +# on the same table let $message= Testcase 3.5.7.15/16:; --source include/show_msg.inc @@ -580,7 +564,6 @@ let $message= Testcase 3.5.7.15/16:; Create trigger trg_3_406010_1 AFTER DELETE on tb3 for each row set @test_var=@test_var+5; - --error ER_NOT_SUPPORTED_YET Create trigger trg_3_406010_2 AFTER DELETE on tb3 for each row set @test_var=@test_var+50; @@ -601,7 +584,6 @@ let $message= Testcase 3.5.7.15/16:; #Cleanup --disable_warnings drop trigger trg_3_406010_1; - --error 0, ER_TRG_DOES_NOT_EXIST drop trigger trg_3_406010_2; delete from tb3 where f121='Test 3.5.7.15/16'; --enable_warnings diff --git a/mysql-test/suite/roles/definer.result b/mysql-test/suite/roles/definer.result index 4810e597763..e3b2d6ac758 100644 --- a/mysql-test/suite/roles/definer.result +++ b/mysql-test/suite/roles/definer.result @@ -108,9 +108,9 @@ set role role1; create definer=current_role trigger tr1 before insert on t2 for each row insert t1 values (111, 222, 333); show create trigger tr1; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created tr1 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`role1` trigger tr1 before insert on t2 for each row -insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci +insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci # set role none; insert t2 values (11,22,33); ERROR 42000: INSERT command denied to user ''@'' for table 't1' @@ -125,9 +125,9 @@ a b c create definer=role2 trigger tr2 before delete on t2 for each row insert t1 values (111, 222, 333); show create trigger tr2; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created tr2 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`role2` trigger tr2 before delete on t2 for each row -insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci +insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci # delete from t2 where a=1; select * from t1; a b c @@ -143,9 +143,9 @@ insert t1 values (111, 222, 333); Warnings: Note 1449 The user specified as a definer ('role3'@'%') does not exist show create trigger tr3; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created tr3 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`role3`@`%` trigger tr3 before update on t2 for each row -insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci +insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci # update t2 set b=2 where a=2; ERROR HY000: The user specified as a definer ('role3'@'%') does not exist select * from t1; @@ -157,9 +157,9 @@ a b c 2 20 200 flush tables; show create trigger tr2; -Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created tr2 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`role2`@`` trigger tr2 before delete on t2 for each row -insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci +insert t1 values (111, 222, 333) latin1 latin1_swedish_ci latin1_swedish_ci # delete from t2 where a=2; ERROR HY000: The user specified as a definer ('role2'@'%') does not exist select * from t1; diff --git a/mysql-test/suite/roles/definer.test b/mysql-test/suite/roles/definer.test index 090c60917c9..a4a65a77a9b 100644 --- a/mysql-test/suite/roles/definer.test +++ b/mysql-test/suite/roles/definer.test @@ -138,6 +138,7 @@ create definer=current_role trigger tr1 before insert on t2 for each row set role role1; create definer=current_role trigger tr1 before insert on t2 for each row insert t1 values (111, 222, 333); +--replace_column 7 # show create trigger tr1; set role none; @@ -149,6 +150,7 @@ select * from t2; # definer=role_name, privileges ok create definer=role2 trigger tr2 before delete on t2 for each row insert t1 values (111, 222, 333); +--replace_column 7 # show create trigger tr2; delete from t2 where a=1; select * from t1; @@ -158,6 +160,7 @@ delete from t1 where a=111; # definer=non_existent_role create definer=role3 trigger tr3 before update on t2 for each row insert t1 values (111, 222, 333); +--replace_column 7 # show create trigger tr3; --error ER_NO_SUCH_USER update t2 set b=2 where a=2; @@ -178,6 +181,7 @@ open(F, '>', $f) or die "open(>$f): $!"; syswrite F, $_ or die "syswrite($f): $!" EOF +--replace_column 7 # show create trigger tr2; --error ER_NO_SUCH_USER delete from t2 where a=2; diff --git a/mysql-test/suite/rpl/r/rpl_ddl.result b/mysql-test/suite/rpl/r/rpl_ddl.result index 7bb9bd02cba..68c5e91f42e 100644 --- a/mysql-test/suite/rpl/r/rpl_ddl.result +++ b/mysql-test/suite/rpl/r/rpl_ddl.result @@ -1267,11 +1267,11 @@ TEST-INFO: SLAVE: The INSERT is committed (Succeeded) connection master; SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @a:=1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection slave; SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 SET @a:=1 BEFORE # root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection master; ######## DROP TRIGGER trg1 ######## diff --git a/mysql-test/suite/rpl/r/rpl_replicate_do.result b/mysql-test/suite/rpl/r/rpl_replicate_do.result index c7ac37a9654..115c27d9387 100644 --- a/mysql-test/suite/rpl/r/rpl_replicate_do.result +++ b/mysql-test/suite/rpl/r/rpl_replicate_do.result @@ -39,8 +39,8 @@ t1 t2 show triggers; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 set new.b=2 BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci -trg2 INSERT t2 set new.b=2 BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 set new.b=2 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg2 INSERT t2 set new.b=2 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection slave; connection slave; show tables; @@ -48,7 +48,7 @@ Tables_in_test t1 show triggers; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 set new.b=2 BEFORE NULL NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 set new.b=2 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci connection master; drop trigger trg1; drop trigger trg2; diff --git a/mysql-test/suite/rpl/r/rpl_trigger.result b/mysql-test/suite/rpl/r/rpl_trigger.result index 729d31fb001..dcf0c70ffc4 100644 --- a/mysql-test/suite/rpl/r/rpl_trigger.result +++ b/mysql-test/suite/rpl/r/rpl_trigger.result @@ -972,7 +972,7 @@ t1 t2 SHOW TRIGGERS; Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation -trg1 INSERT t1 INSERT INTO t2 VALUES(CURRENT_USER()) AFTER NULL latin1 latin1_swedish_ci latin1_swedish_ci +trg1 INSERT t1 INSERT INTO t2 VALUES(CURRENT_USER()) AFTER # latin1 latin1_swedish_ci latin1_swedish_ci SELECT * FROM t1; c 1 @@ -1115,4 +1115,47 @@ Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # use `test`; drop trigger if exists notexistent connection master; +create table t1 (a int primary key, b int); +create trigger tr3 +before insert on t1 +for each row set NEW.b := (NEW.b+1)*4; +create trigger tr1 +before insert on t1 +for each row precedes tr3 set NEW.b := (NEW.b+1)*2; +create trigger tr2 +before insert on t1 +for each row follows tr1 set NEW.b := (NEW.b+1)*3; +show triggers; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr1 INSERT t1 set NEW.b := (NEW.b+1)*2 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr2 INSERT t1 set NEW.b := (NEW.b+1)*3 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr3 INSERT t1 set NEW.b := (NEW.b+1)*4 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +insert into t1 values (1,1); +select * from t1; +a b +1 64 +connection slave; +show triggers; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr1 INSERT t1 set NEW.b := (NEW.b+1)*2 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr2 INSERT t1 set NEW.b := (NEW.b+1)*3 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +tr3 INSERT t1 set NEW.b := (NEW.b+1)*4 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +select * from t1; +a b +1 64 +connection master; +drop table t1; +CREATE TABLE t1 (i INT); +CREATE OR REPLACE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @a=1; +CREATE OR REPLACE TRIGGER tr BEFORE DELETE ON t1 FOR EACH ROW PRECEDES non_existing_trigger SET @a=2; +ERROR HY000: Referenced trigger 'non_existing_trigger' for the given action time and event type does not exist +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr INSERT t1 SET @a=1 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +connection slave; +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +tr INSERT t1 SET @a=1 BEFORE # NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION root@localhost latin1 latin1_swedish_ci latin1_swedish_ci +connection master; +drop table t1; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_replicate_do.test b/mysql-test/suite/rpl/t/rpl_replicate_do.test index e2b488394d1..66ddf2dfe0a 100644 --- a/mysql-test/suite/rpl/t/rpl_replicate_do.test +++ b/mysql-test/suite/rpl/t/rpl_replicate_do.test @@ -41,18 +41,22 @@ create trigger trg1 before insert on t1 for each row set new.b=2; create table t2 (a int, b int); create trigger trg2 before insert on t2 for each row set new.b=2; show tables; +--replace_column 6 # show triggers; sync_slave_with_master; connection slave; show tables; +--replace_column 6 # show triggers; connection master; drop trigger trg1; drop trigger trg2; +--replace_column 6 # show triggers; sync_slave_with_master; connection slave; show tables; +--replace_column 6 # show triggers; connection master; drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test index 83097e7bd0a..f692816bf82 100644 --- a/mysql-test/suite/rpl/t/rpl_trigger.test +++ b/mysql-test/suite/rpl/t/rpl_trigger.test @@ -337,6 +337,7 @@ SELECT MASTER_POS_WAIT('master-bin.000001', 513) >= 0; # Check that the replication succeeded. SHOW TABLES LIKE 't_'; +--replace_column 6 # SHOW TRIGGERS; SELECT * FROM t1; SELECT * FROM t2; @@ -367,6 +368,7 @@ RESET SLAVE; connection master; SHOW TABLES LIKE 't_'; +--replace_column 6 # SHOW TRIGGERS; RESET MASTER; @@ -534,6 +536,49 @@ let $binlog_start= $slave_pos; source include/show_binlog_events.inc; connection master; +# +# MDEV-6112 multiple triggers per table +# + +create table t1 (a int primary key, b int); +create trigger tr3 + before insert on t1 + for each row set NEW.b := (NEW.b+1)*4; +create trigger tr1 + before insert on t1 + for each row precedes tr3 set NEW.b := (NEW.b+1)*2; +create trigger tr2 + before insert on t1 + for each row follows tr1 set NEW.b := (NEW.b+1)*3; + +--replace_column 6 # +show triggers; +insert into t1 values (1,1); +select * from t1; +sync_slave_with_master; +--replace_column 6 # +show triggers; +select * from t1; +connection master; +drop table t1; + +# +# MDEV-10924 CREATE OR REPLACE TRIGGER which fails on PRECEDES/FOLLOWS drops +# the trigger, but isn't written to binlog; replication fails +# + +CREATE TABLE t1 (i INT); +CREATE OR REPLACE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW SET @a=1; +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE OR REPLACE TRIGGER tr BEFORE DELETE ON t1 FOR EACH ROW PRECEDES non_existing_trigger SET @a=2; +--replace_column 6 # +SHOW TRIGGERS; +--sync_slave_with_master +--replace_column 6 # +SHOW TRIGGERS; +connection master; +drop table t1; + # # End of tests # diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 0fd3e31a5b4..d619fed240f 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1297,7 +1297,6 @@ BEGIN UPDATE A SET `pk`=1 WHERE `pk`=0 ; END ;| ---error ER_NOT_SUPPORTED_YET CREATE TRIGGER f1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN UPDATE A SET `pk`=1 WHERE `pk`=0 ; diff --git a/mysql-test/t/create_drop_trigger.test b/mysql-test/t/create_drop_trigger.test index a8afc8716d6..0f19f5cf09f 100644 --- a/mysql-test/t/create_drop_trigger.test +++ b/mysql-test/t/create_drop_trigger.test @@ -6,7 +6,6 @@ SET @sum=0; INSERT INTO t1 VALUES (10), (20), (30); SELECT @sum; ---error ER_NOT_SUPPORTED_YET CREATE TRIGGER IF NOT EXISTS val_sum_new BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val; CREATE TRIGGER IF NOT EXISTS val_sum AFTER INSERT ON t1 FOR EACH ROW SET @sum = @sum + 1 + NEW.val; diff --git a/mysql-test/t/features.test b/mysql-test/t/features.test index 63e923a772b..1241bd50bdd 100644 --- a/mysql-test/t/features.test +++ b/mysql-test/t/features.test @@ -98,6 +98,7 @@ set @a:=0; select @a; insert into t1 values (1),(2); select @a; +--replace_column 6 # SHOW TRIGGERS IN test like 't1'; drop trigger trg; drop table t1; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 13f368b6dbe..1443f654809 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -576,7 +576,9 @@ begin end if; end| delimiter ;| +--replace_column 6 # show triggers; +--replace_column 17 # select * from information_schema.triggers where trigger_schema in ('mysql', 'information_schema', 'test', 'mysqltest'); drop trigger trg1; @@ -1034,12 +1036,14 @@ grant select(b) on mysqltest.t1 to mysqltest_1@localhost; select trigger_name from information_schema.triggers where event_object_table='t1'; +--replace_column 6 # show triggers from mysqltest; connect (con27629,localhost,mysqltest_1,,mysqltest); show columns from t1; select column_name from information_schema.columns where table_name='t1'; +--replace_column 6 # show triggers; select trigger_name from information_schema.triggers where event_object_table='t1'; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index faa420fd275..689c52faabc 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1678,6 +1678,7 @@ CREATE TABLE t1(a int); CREATE TABLE t2(a int); CREATE TABLE t3(a int) ENGINE = MERGE UNION(t1, t2); CREATE TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo(); +--replace_column 7 # SHOW CREATE TRIGGER tr1; DROP TRIGGER tr1; DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/mysql_comments.test b/mysql-test/t/mysql_comments.test index 7b00f17e259..fb0e5f94950 100644 --- a/mysql-test/t/mysql_comments.test +++ b/mysql-test/t/mysql_comments.test @@ -30,10 +30,12 @@ drop trigger if exists t1_bi; # Test without comments --echo "Pass 1 : --disable-comments" +--replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2})*/--TIME--/ --exec $MYSQL --disable-comments test 2>&1 < "./t/mysql_comments.sql" # Test with comments --echo "Pass 2 : --enable-comments" +--replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2})*/--TIME--/ --exec $MYSQL --enable-comments test 2>&1 < "./t/mysql_comments.sql" diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index ccc68485bd6..299698ed04b 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1007,6 +1007,7 @@ SELECT * FROM `test2`; #DROP TABLE test2; # restore --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqldump.sql +--replace_column 6 # SHOW TRIGGERS; SELECT * FROM `test1`; SELECT * FROM `test2`; @@ -2053,6 +2054,7 @@ CREATE PROCEDURE pr1 () SELECT "Meow"; CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT "Meow"; --echo +--replace_column 6 # SHOW TRIGGERS; SHOW EVENTS; SELECT name,body FROM mysql.proc WHERE NAME = 'pr1'; @@ -2071,6 +2073,7 @@ DROP PROCEDURE pr1; --echo --echo reload table; this should restore table and trigger --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/t1.sql +--replace_column 6 # SHOW TRIGGERS; SHOW EVENTS; SELECT name,body FROM mysql.proc WHERE NAME = 'pr1'; @@ -2078,6 +2081,7 @@ SELECT name,body FROM mysql.proc WHERE NAME = 'pr1'; --echo --echo reload db; this should restore routines and events --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/test_34861.sql +--replace_column 6 # SHOW TRIGGERS; SHOW EVENTS; SELECT name,body FROM mysql.proc WHERE NAME = 'pr1'; @@ -2311,13 +2315,13 @@ CREATE VIEW v2 AS SELECT * FROM t2; --echo # Dumping BUG52792 database in xml format. --echo --echo # Running 'replace_regex on timestamp' ---replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/--TIME--/ +--replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2})*/--TIME--/ --exec $MYSQL_DUMP --user=root --compact -R -E --triggers -X BUG52792 --echo --echo # Dumping BUG52792 database in xml format with comments. --echo --echo # Running 'replace_regex on timestamp' ---replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/--TIME--/ +--replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2})*/--TIME--/ --exec $MYSQL_DUMP --comments --user=root -R -E --triggers -X BUG52792 --echo @@ -2330,7 +2334,8 @@ connect (conn_1, localhost, user1, , BUG52792, $MASTER_MYPORT, $MASTER_MYSOCK); connection conn_1; --echo # Running 'replace_regex on timestamp' ---replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/--TIME--/ +--replace_regex /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{2})*/--TIME--/ + --replace_result mysqldump.exe mysqldump --error 2 --exec $MYSQL_DUMP --user=user1 -R -E --triggers -X BUG52792 diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index a14c42d8ade..13ca9a528c6 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -774,6 +774,7 @@ SHOW COLUMNS FROM t1; --echo ---------------------------------------------------------------- +--replace_column 6 # SHOW TRIGGERS LIKE 't1'; --echo ---------------------------------------------------------------- @@ -799,6 +800,14 @@ SELECT FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name = 't1_bi'; +# Metadata is different for the field "CREATED" with and without --ps +# So test it separately. + +--disable_ps_protocol +--replace_column 1 # +SELECT CREATED FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_name='t1_bi'; +--enable_ps_protocol + --echo ---------------------------------------------------------------- SHOW CREATE VIEW v1; @@ -1092,32 +1101,53 @@ CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1; # Test. +--replace_column 7 # SHOW CREATE TRIGGER t1_bi; CREATE PROCEDURE p1() SHOW CREATE TRIGGER t1_bi; +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); +--replace_column 7 # CALL p1(); PREPARE stmt1 FROM 'SHOW CREATE TRIGGER t1_bi'; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; +--replace_column 7 # EXECUTE stmt1; # Cleanup. @@ -1178,6 +1208,7 @@ SHOW CREATE PROCEDURE p1; SHOW CREATE FUNCTION f1; +--replace_column 7 # SHOW CREATE TRIGGER t1_bi; SHOW CREATE EVENT ev1; @@ -1291,6 +1322,7 @@ LOCK TABLE t1 WRITE; connection default; # Should not block. +--replace_column 7 # SHOW CREATE TRIGGER t1_bi; connection con1; @@ -1300,6 +1332,7 @@ UNLOCK TABLES; connection default; START TRANSACTION; +--replace_column 7 # SHOW CREATE TRIGGER t1_bi; connection con1; diff --git a/mysql-test/t/trigger-compat.test b/mysql-test/t/trigger-compat.test index 2d949b0c91e..437df89b4b1 100644 --- a/mysql-test/t/trigger-compat.test +++ b/mysql-test/t/trigger-compat.test @@ -90,6 +90,7 @@ SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_n --echo +--replace_column 17 # SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; # Clean up @@ -181,6 +182,7 @@ FLUSH TABLE t2; CREATE TRIGGER tr16 AFTER UPDATE ON t1 FOR EACH ROW INSERT INTO t1 VALUES (1); --error ER_PARSE_ERROR CREATE TRIGGER tr22 BEFORE INSERT ON t2 FOR EACH ROW DELETE FROM non_existing_table; +--replace_column 6 # SHOW TRIGGERS; --error ER_PARSE_ERROR INSERT INTO t1 VALUES (1); @@ -193,6 +195,7 @@ UPDATE t1 SET a = 1 WHERE a = 1; SELECT * FROM t1; --error ER_PARSE_ERROR RENAME TABLE t1 TO t1_2; +--replace_column 6 # SHOW TRIGGERS; DROP TRIGGER tr11; @@ -201,6 +204,7 @@ DROP TRIGGER tr13; DROP TRIGGER tr14; DROP TRIGGER tr15; +--replace_column 6 # SHOW TRIGGERS; --echo # Make sure there is no trigger file left. @@ -257,7 +261,7 @@ INSERT INTO t2 VALUES (1), (2), (3); --echo # We write three trigger files. First trigger is syntaxically incorrect, next trigger is correct --echo # and last trigger is broken. ---echo # Next we try to execute SHOW CREATE TRGGIR command for broken trigger and then try to drop one. +--echo # Next we try to execute SHOW CREATE TRIGGER command for broken trigger and then try to drop one. --write_file $MYSQLD_DATADIR/test/tr11.TRN TYPE=TRIGGERNAME trigger_table=t1 diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index a02dce34837..050bd5ea56e 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -324,8 +324,8 @@ create trigger trg before insert on t2 for each row set @a:=1; create trigger trg before insert on t1 for each row set @a:=1; --error ER_TRG_ALREADY_EXISTS create trigger trg after insert on t1 for each row set @a:=1; ---error ER_NOT_SUPPORTED_YET create trigger trg2 before insert on t1 for each row set @a:=1; +drop trigger trg2; --error ER_TRG_ALREADY_EXISTS create trigger trg before insert on t3 for each row set @a:=1; create trigger trg2 before insert on t3 for each row set @a:=1; @@ -2238,9 +2238,9 @@ create table t1 (i int, j int); create trigger t1_bi before insert on t1 for each row begin end; --error ER_TRG_ALREADY_EXISTS create trigger t1_bi before insert on t1 for each row begin end; ---error ER_NOT_SUPPORTED_YET create trigger t1_bi2 before insert on t1 for each row begin end; drop trigger t1_bi; +drop trigger t1_bi2; --error ER_TRG_DOES_NOT_EXIST drop trigger t1_bi; @@ -2392,6 +2392,7 @@ CREATE TABLE t2 (a INT); CREATE TRIGGER trg1 BEFORE INSERT ON t2 FOR EACH ROW INSERT/*!INTO*/t1 VALUES (1); --echo # Used to crash +--replace_column 6 # SHOW TRIGGERS IN db1; --error ER_PARSE_ERROR INSERT INTO t2 VALUES (1); @@ -2614,8 +2615,11 @@ DROP TABLE t1, t2; # # MDEV-4829 BEFORE INSERT triggers dont issue 1406 error +# Also check timestamp for trigger # +set time_zone="+00:00"; +SET TIMESTAMP=UNIX_TIMESTAMP('2001-01-01 10:20:30'); SET @@session.sql_mode = 'STRICT_ALL_TABLES,STRICT_TRANS_TABLES'; CREATE TABLE t1 (c CHAR(1) NOT NULL); DELIMITER |; @@ -2631,6 +2635,42 @@ DELIMITER ;| SET @@session.sql_mode = default; --error ER_DATA_TOO_LONG INSERT INTO t1 VALUES ('a'); +show create trigger t1_bi; DROP TRIGGER t1_bi; DROP TABLE t1; +SET TIMESTAMP=DEFAULT; +set time_zone= @@global.time_zone; +# +# MDEV-10915 Count number of exceuted triggers +# + +create table t1 (i int); +create trigger tr1 after insert on t1 for each row set @a=@a+1; +create trigger tr2 after insert on t1 for each row set @a=@a+1; +create trigger tr3 after insert on t1 for each row set @a=@a+1; +flush status; +show status like 'Executed_triggers'; +set @a=0; +insert into t1 values (1); +show status like 'Executed_triggers'; +select @a; +drop table t1; + +# +# MDEV-10916 In trigger's CREATED time microseconds are misinterpreted +# + +create table t1 (i int); +set time_zone="+0:00"; +SET TIMESTAMP=UNIX_TIMESTAMP('2016-01-01 10:10:10.33'); +select now(2); +create or replace trigger tr1 after insert on t1 for each row set @a=@a+1; +SET TIMESTAMP=UNIX_TIMESTAMP('2016-01-01 10:10:10.99'); +select now(2); +create or replace trigger tr2 after insert on t1 for each row set @a=@a+1; +select now(2); +select trigger_name, action_order, created from information_schema.triggers + where event_object_table = 't1' and trigger_schema='test'; +drop table t1; +set time_zone= @@global.time_zone; diff --git a/mysql-test/t/trigger_notembedded.test b/mysql-test/t/trigger_notembedded.test index df5637790af..a31594826e7 100644 --- a/mysql-test/t/trigger_notembedded.test +++ b/mysql-test/t/trigger_notembedded.test @@ -281,6 +281,7 @@ INSERT INTO t1 VALUES(6); # Check that SHOW TRIGGERS statement provides "Definer" column. # +--replace_column 6 # SHOW TRIGGERS; # @@ -339,6 +340,7 @@ SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_n --echo +--replace_column 17 # SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name; # diff --git a/mysql-test/t/trigger_wl3253.test b/mysql-test/t/trigger_wl3253.test new file mode 100644 index 00000000000..3504eeaf889 --- /dev/null +++ b/mysql-test/t/trigger_wl3253.test @@ -0,0 +1,428 @@ +--echo # +--echo # WL#3253: multiple triggers per table +--echo # + +SET @binlog_format_saved = @@binlog_format; +SET binlog_format=ROW; +SET time_zone='+00:00'; + +--echo # +--echo # Test 1. +--echo # Check that the sequence of triggers for the same combination +--echo # of event type/action type can be created for a table +--echo # and is fired consequently in the order of its creation +--echo # during statement execution. +--echo # In this test we check BEFORE triggers. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); + +INSERT INTO t1 VALUES (1); + +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 2. +--echo # Check that the sequence of triggers for the same combination +--echo # of event type/action type can be created for a table +--echo # and is fired consequently in the order of its creation +--echo # during statement execution. +--echo # In this test we check AFTER triggers. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a); +CREATE TRIGGER tr2_bi AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); + +INSERT INTO t1 VALUES (1); + +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 3. +--echo # Check that the sequences of triggers for the different event types +--echo # can be created for a table and are fired consequently +--echo # in the order of its creation during statement execution. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); + +CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a); +CREATE TRIGGER tr2_bu BEFORE UPDATE ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300); + +INSERT INTO t1 VALUES (1); + +SELECT * FROM t2 ORDER BY b; + +UPDATE t1 SET a = 5; + +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 4. +--echo # Check that every new created trigger has unique action_order value +--echo # started from 1 and NOT NULL value for creation timestamp. +--echo # + +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; +SET TIMESTAMP=UNIX_TIMESTAMP('2013-01-31 09:00:01'); +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'; + +DROP TABLE t1; +SET TIMESTAMP=DEFAULT; + +--echo # +--echo # Test 5. +--echo # Check that action_order attribute isn't shown +--echo # in the output of SHOW TRIGGERS and SHOW CREATE TRIGGER +--echo # + +CREATE TABLE t1 (a INT); +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; + +--replace_column 6 # +SHOW TRIGGERS; + +--replace_column 17 # +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'test'; + +--replace_column 7 # +SHOW CREATE TRIGGER tr1_bi; + +DROP TABLE t1; + +--echo # +--echo # Test 6. +--echo # Check that action_order attribute is reused when trigger +--echo # are recreated. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +DROP TRIGGER tr1_bi; + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=2; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +DROP TABLE t1; + +--echo # +--echo # Test 7. +--echo # Check that it is possible to create several triggers with +--echo # the same value for creation timestamp. +--echo # + +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; +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'; + +DROP TABLE t1; +SET TIMESTAMP=DEFAULT; + +--echo # +--echo # Test 8. +--echo # Check that SHOW CREATE TRIGGER outputs the CREATED attribute +--echo # and it is not NULL +--echo # + +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; + +DROP TABLE t1; +SET TIMESTAMP=DEFAULT; + +--echo # +--echo # Test 9. +--echo # Check that SHOW TRIGGERS outputs the CREATED attribute +--echo # and it is not NULL. +--echo # + +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; + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'test'; + +DROP TABLE t1; + +SET TIMESTAMP=DEFAULT; + +--echo # +--echo # Test 10. +--echo # Check that FOLLOWS clause is supported and works correctly. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi INSERT INTO t2 (a) VALUES (NEW.a + 200); + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +INSERT INTO t1 VALUES (1); +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 11. +--echo # Check that PRECEDES clause is supported and works correctly. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 300); +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr3_bi INSERT INTO t2 (a) VALUES (NEW.a + 200); + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +INSERT INTO t1 VALUES (1); +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 12. +--echo # Check that the PRECEDES works properly for the 1st trigger in the chain. +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT, b INT AUTO_INCREMENT PRIMARY KEY); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 (a) VALUES (NEW.a + 100); +CREATE TRIGGER tr0_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr1_bi INSERT INTO t2 (a) VALUES (NEW.a); + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +INSERT INTO t1 VALUES (1); +SELECT * FROM t2 ORDER BY b; + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # Test 13. +--echo # Check that error is reported if the FOLLOWS clause references to +--echo # non-existing trigger +--echo # + +CREATE TABLE t1 (a INT); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr0_bi SET @a:=2; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +DROP TABLE t1; + +--echo # +--echo # Test 14. +--echo # Check that error is reported if the PRECEDES clause references to +--echo # non-existing trigger +--echo # + +CREATE TABLE t1 (a INT); + +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr2_bi BEFORE INSERT ON t1 FOR EACH ROW PRECEDES tr0_bi SET @a:=2; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +DROP TABLE t1; + +--echo # +--echo # Test 15. +--echo # Check that action_order value is independent for each type of event +--echo # (INSERT/UPDATE/DELETE) +--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; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +CREATE TRIGGER tr3_bi BEFORE INSERT ON t1 FOR EACH ROW FOLLOWS tr2_bi SET @a:=3; +CREATE TRIGGER tr2_bu BEFORE UPDATE ON t1 FOR EACH ROW FOLLOWS tr1_bu SET @a:=3; + +SELECT trigger_name, action_order FROM information_schema.triggers WHERE trigger_schema='test'; + +DROP TABLE t1; + +--echo # +--echo # Test 16. +--echo # Check that the trigger in the clause FOLLOWS/PRECEDES can refences +--echo # only to the trigger for the same ACTION/TIMINMG +--echo # + +CREATE TABLE t1 (a INT); +CREATE TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +CREATE TRIGGER tr1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr2_bu BEFORE UPDATE ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr2_au AFTER UPDATE ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr1_au AFTER UPDATE ON t1 FOR EACH ROW FOLLOWS tr1_bu SET @a:=3; + +--error ER_REFERENCED_TRG_DOES_NOT_EXIST +CREATE TRIGGER tr1_ai AFTER INSERT ON t1 FOR EACH ROW FOLLOWS tr1_bi SET @a:=3; + +--replace_column 6 # +SHOW TRIGGERS; + +--replace_column 17 # +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'test'; + +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 + +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 # + +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 + +DROP TABLE t1; + +--echo # +--echo # Test 19. Check that table's triggers are dumped correctly in xml. +--echo # + +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 + +DROP TABLE t1; + +--echo # +--echo # Test 20. Check that the statement CHECK TABLE FOR UPGRADE outputs +--echo # the warnings for triggers created by a server without support for wl3253. +--echo # + +CREATE TABLE t1 (a INT); + +let $MYSQLD_DATADIR=`SELECT @@datadir`; +--write_file $MYSQLD_DATADIR/test/t1.TRG +TYPE=TRIGGERS +triggers='CREATE DEFINER=`root`@`localhost` TRIGGER tr1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1' 'CREATE DEFINER=`root`@`localhost` TRIGGER tr1_ai AFTER INSERT ON t1 FOR EACH ROW SET @a:=2' +sql_modes=1073741824 1073741824 +definers='root@localhost' 'root@localhost' +client_cs_names='latin1' 'latin1' +connection_cl_names='latin1_swedish_ci' 'latin1_swedish_ci' +db_cl_names='latin1_swedish_ci' 'latin1_swedish_ci' +EOF + +--write_file $MYSQLD_DATADIR/test/tr1_bi.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +--write_file $MYSQLD_DATADIR/test/tr1_ai.TRN +TYPE=TRIGGERNAME +trigger_table=t1 +EOF + +FLUSH TABLE t1; + +CHECK TABLE t1 FOR UPGRADE; + +SHOW TRIGGERS; + +SELECT * FROM INFORMATION_SCHEMA.TRIGGERS WHERE trigger_schema = 'test'; + +SHOW CREATE TRIGGER tr1_bi; +SHOW CREATE TRIGGER tr1_ai; + +DROP TABLE t1; + +SET binlog_format=@binlog_format_saved; + +--echo # End of tests. +--echo # diff --git a/sql/item.cc b/sql/item.cc index 61635ea4ca8..ceb05911a63 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8694,7 +8694,7 @@ void Item_insert_value::print(String *str, enum_query_type query_type) this stage we can't say exactly what Field object (corresponding to TABLE::record[0] or TABLE::record[1]) should be bound to this Item, we only find out index of the Field and then select concrete - Field object in fix_fields() (by that time Table_trigger_list::old_field/ + Field object in fix_fields() (by that time Table_triggers_list::old_field/ new_field should point to proper array of Fields). It also binds Item_trigger_field to Table_triggers_list object for table of trigger which uses this item. diff --git a/sql/lex.h b/sql/lex.h index 003e88d2d9d..d82dcf4e94a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -240,6 +240,7 @@ static SYMBOL symbols[] = { { "FLOAT8", SYM(DOUBLE_SYM)}, { "FLUSH", SYM(FLUSH_SYM)}, { "FOLLOWING", SYM(FOLLOWING_SYM)}, + { "FOLLOWS", SYM(FOLLOWS_SYM)}, { "FOR", SYM(FOR_SYM)}, { "FORCE", SYM(FORCE_SYM)}, { "FOREIGN", SYM(FOREIGN)}, @@ -447,6 +448,7 @@ static SYMBOL symbols[] = { { "POINT", SYM(POINT_SYM)}, { "POLYGON", SYM(POLYGON)}, { "PORT", SYM(PORT_SYM)}, + { "PRECEDES", SYM(PRECEDES_SYM)}, { "PRECEDING", SYM(PRECEDING_SYM)}, { "PRECISION", SYM(PRECISION)}, { "PREPARE", SYM(PREPARE_SYM)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a5cfd0527e8..0c742a5c484 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2147,7 +2147,10 @@ static void mysqld_exit(int exit_code) shutdown_performance_schema(); // we do it as late as possible #endif set_malloc_size_cb(NULL); - DBUG_ASSERT(global_status_var.global_memory_used == 0); + if (!opt_debugging) + { + DBUG_ASSERT(global_status_var.global_memory_used == 0); + } cleanup_tls(); DBUG_LEAVE; if (opt_endinfo && global_status_var.global_memory_used) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 9d31667a6a8..273c0afb9ac 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -330,11 +330,7 @@ bool partition_info::can_prune_insert(THD* thd, partitioning column, since they may change the row to be in another partition. */ - if (table->triggers && - table->triggers->has_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE) && - table->triggers->is_fields_updated_in_trigger(&full_part_field_set, - TRG_EVENT_INSERT, - TRG_ACTION_BEFORE)) + if (is_fields_updated_in_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE)) DBUG_RETURN(false); if (table->found_next_number_field) @@ -371,15 +367,8 @@ bool partition_info::can_prune_insert(THD* thd, partitioning column, since they may change the row to be in another partition. */ - if (table->triggers && - table->triggers->has_triggers(TRG_EVENT_UPDATE, - TRG_ACTION_BEFORE) && - table->triggers->is_fields_updated_in_trigger(&full_part_field_set, - TRG_EVENT_UPDATE, - TRG_ACTION_BEFORE)) - { + if (is_fields_updated_in_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE)) DBUG_RETURN(false); - } } /* diff --git a/sql/partition_info.h b/sql/partition_info.h index 66579be6384..99a71fea798 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -375,6 +375,20 @@ public: MY_BITMAP *used_partitions); bool has_same_partitioning(partition_info *new_part_info); private: + bool is_fields_updated_in_triggers(trg_event_type event_type, + trg_action_time_type action_time_type) + { + if (table->triggers) + { + Trigger *t; + for (t= table->triggers->get_trigger(event_type, action_time_type); + t; + t= t->next) + if (t->is_fields_updated_in_trigger(&full_part_field_set)) + return true; + } + return false; + } static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, uint start_no); diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 3272d2a41f0..03d4b150434 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -419,6 +419,7 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, { sys_var *svar; LEX_STRING var; + uint not_used; lasts= (char *) memchr(token, separator, rest); @@ -432,7 +433,7 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, var.length= rest; /* Remove leading/trailing whitespace. */ - trim_whitespace(char_set, &var); + trim_whitespace(char_set, &var, ¬_used); if(!strcmp(var.str,(const char *)"*")) { @@ -500,6 +501,7 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, for (;;) { LEX_STRING var; + uint not_used; lasts= (char *) memchr(token, separator, rest); @@ -513,7 +515,7 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, var.length= rest; /* Remove leading/trailing whitespace. */ - trim_whitespace(char_set, &var); + trim_whitespace(char_set, &var, ¬_used); if(!strcmp(var.str,(const char *)"*") && !find_sys_var_ex(thd, var.str, var.length, throw_error, true)) diff --git a/sql/set_var.h b/sql/set_var.h index ba8027edc72..ee62f6db7ec 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -411,7 +411,7 @@ inline bool IS_SYSVAR_AUTOSIZE(void *ptr) bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type); ulonglong expand_sql_mode(ulonglong sql_mode); -bool sql_mode_string_representation(THD *thd, ulonglong sql_mode, LEX_STRING *ls); +bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode, LEX_STRING *ls); int default_regex_flags_pcre(const THD *thd); extern sys_var *Sys_autocommit_ptr; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 4d3861b2936..c555d9c732c 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7230,3 +7230,5 @@ ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000 ER_PARTITION_DEFAULT_ERROR eng "Only one DEFAULT partition allowed" ukr "ะŸั€ะธะฟัƒัั‚ะธะผะพ ะผะฐั‚ะธ ั‚ั–ะปัŒะบะธ ะพะดะธะฝ DEFAULT ั€ะพะทะดั–ะป" +ER_REFERENCED_TRG_DOES_NOT_EXIST + eng "Referenced trigger '%s' for the given action time and event type does not exist" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 41006f07a0a..37479c14047 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -707,6 +707,7 @@ sp_head::set_stmt_end(THD *thd) { Lex_input_stream *lip= & thd->m_parser_state->m_lip; /* shortcut */ const char *end_ptr= lip->get_cpp_ptr(); /* shortcut */ + uint not_used; /* Make the string of parameters. */ @@ -724,7 +725,7 @@ sp_head::set_stmt_end(THD *thd) m_body.length= end_ptr - m_body_begin; m_body.str= thd->strmake(m_body_begin, m_body.length); - trim_whitespace(thd->charset(), & m_body); + trim_whitespace(thd->charset(), &m_body, ¬_used); /* Make the string of UTF-body. */ @@ -732,7 +733,7 @@ sp_head::set_stmt_end(THD *thd) m_body_utf8.length= lip->get_body_utf8_length(); m_body_utf8.str= thd->strmake(lip->get_body_utf8_str(), m_body_utf8.length); - trim_whitespace(thd->charset(), & m_body_utf8); + trim_whitespace(thd->charset(), &m_body_utf8, ¬_used); /* Make the string of whole stored-program-definition query (in the @@ -741,7 +742,7 @@ sp_head::set_stmt_end(THD *thd) m_defstr.length= end_ptr - lip->get_cpp_buf(); m_defstr.str= thd->strmake(lip->get_cpp_buf(), m_defstr.length); - trim_whitespace(thd->charset(), & m_defstr); + trim_whitespace(thd->charset(), &m_defstr, ¬_used); } diff --git a/sql/sql_base.h b/sql/sql_base.h index f487887ddc9..bdfbe400e54 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -16,8 +16,8 @@ #ifndef SQL_BASE_INCLUDED #define SQL_BASE_INCLUDED -#include "sql_trigger.h" /* trg_event_type */ #include "sql_class.h" /* enum_mark_columns */ +#include "sql_trigger.h" /* trg_event_type */ #include "mysqld.h" /* key_map */ #include "table_cache.h" diff --git a/sql/sql_class.h b/sql/sql_class.h index 51642ecf798..9a41a0d4981 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -502,6 +502,8 @@ enum killed_type KILL_TYPE_QUERY }; +typedef ulonglong sql_mode_t; + #include "sql_lex.h" /* Must be here */ class Delayed_insert; @@ -513,8 +515,6 @@ class Time_zone; #define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC) -typedef ulonglong sql_mode_t; - typedef struct system_variables { /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4d161b32577..c53daf7d92d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2013,7 +2013,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd) } -void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str) +void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str, uint *prefix_length) { /* TODO: @@ -2021,8 +2021,10 @@ void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str) that can be considered white-space. */ + *prefix_length= 0; while ((str->length > 0) && (my_isspace(cs, str->str[0]))) { + (*prefix_length)++; str->length --; str->str ++; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6387b6d1c2d..5310e2a018f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -29,7 +29,7 @@ #include "sql_cmd.h" #include "sql_alter.h" // Alter_info #include "sql_window.h" - +#include "sql_trigger.h" /* YACC and LEX Definitions */ @@ -1196,10 +1196,16 @@ struct st_sp_chistics enum enum_sp_data_access daccess; }; -struct st_trg_chistics + + +struct st_trg_chistics: public st_trg_execution_order { enum trg_action_time_type action_time; enum trg_event_type event; + + const char *ordering_clause_begin; + const char *ordering_clause_end; + }; extern sys_var *trg_new_row_fake_var; @@ -3278,7 +3284,8 @@ void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex); int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex); extern int MYSQLlex(union YYSTYPE *yylval, THD *thd); -extern void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str); +extern void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str, + uint *prefix_removed); extern bool is_lex_native_function(const LEX_STRING *name); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c4ca23cba78..de284cbe39d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -92,6 +92,20 @@ enum enum_i_s_events_fields #define USERNAME_WITH_HOST_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2) + +static const LEX_STRING trg_action_time_type_names[]= +{ + { C_STRING_WITH_LEN("BEFORE") }, + { C_STRING_WITH_LEN("AFTER") } +}; + +static const LEX_STRING trg_event_type_names[]= +{ + { C_STRING_WITH_LEN("INSERT") }, + { C_STRING_WITH_LEN("UPDATE") }, + { C_STRING_WITH_LEN("DELETE") } +}; + #ifndef NO_EMBEDDED_ACCESS_CHECKS static const char *grant_names[]={ "select","insert","update","delete","create","drop","reload","shutdown", @@ -6385,43 +6399,56 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, } -static bool store_trigger(THD *thd, TABLE *table, LEX_STRING *db_name, - LEX_STRING *table_name, LEX_STRING *trigger_name, - enum trg_event_type event, - enum trg_action_time_type timing, - LEX_STRING *trigger_stmt, - ulong sql_mode, - LEX_STRING *definer_buffer, - LEX_STRING *client_cs_name, - LEX_STRING *connection_cl_name, - LEX_STRING *db_cl_name) +static bool store_trigger(THD *thd, Trigger *trigger, + TABLE *table, LEX_STRING *db_name, + LEX_STRING *table_name) { CHARSET_INFO *cs= system_charset_info; LEX_STRING sql_mode_rep; + MYSQL_TIME timestamp; + char definer_holder[USER_HOST_BUFF_SIZE]; + LEX_STRING definer_buffer, trigger_stmt, trigger_body; + definer_buffer.str= definer_holder; + + trigger->get_trigger_info(&trigger_stmt, &trigger_body, &definer_buffer); restore_record(table, s->default_values); table->field[0]->store(STRING_WITH_LEN("def"), cs); table->field[1]->store(db_name->str, db_name->length, cs); - table->field[2]->store(trigger_name->str, trigger_name->length, cs); - table->field[3]->store(trg_event_type_names[event].str, - trg_event_type_names[event].length, cs); + table->field[2]->store(trigger->name.str, trigger->name.length, cs); + table->field[3]->store(trg_event_type_names[trigger->event].str, + trg_event_type_names[trigger->event].length, cs); table->field[4]->store(STRING_WITH_LEN("def"), cs); table->field[5]->store(db_name->str, db_name->length, cs); table->field[6]->store(table_name->str, table_name->length, cs); - table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs); + table->field[7]->store(trigger->action_order); + table->field[9]->store(trigger_body.str, trigger_body.length, cs); table->field[10]->store(STRING_WITH_LEN("ROW"), cs); - table->field[11]->store(trg_action_time_type_names[timing].str, - trg_action_time_type_names[timing].length, cs); + table->field[11]->store(trg_action_time_type_names[trigger->action_time].str, + trg_action_time_type_names[trigger->action_time].length, cs); table->field[14]->store(STRING_WITH_LEN("OLD"), cs); table->field[15]->store(STRING_WITH_LEN("NEW"), cs); - sql_mode_string_representation(thd, sql_mode, &sql_mode_rep); + if (trigger->create_time) + { + table->field[16]->set_notnull(); + thd->variables.time_zone->gmt_sec_to_TIME(×tamp, + trigger->create_time/100); + /* timestamp is with 6 digits */ + timestamp.second_part= (trigger->create_time % 100) * 10000; + ((Field_temporal_with_date*) table->field[16])->store_time_dec(×tamp, + 2); + } + + sql_mode_string_representation(thd, trigger->sql_mode, &sql_mode_rep); table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs); - table->field[18]->store(definer_buffer->str, definer_buffer->length, cs); - table->field[19]->store(client_cs_name->str, client_cs_name->length, cs); - table->field[20]->store(connection_cl_name->str, - connection_cl_name->length, cs); - table->field[21]->store(db_cl_name->str, db_cl_name->length, cs); + table->field[18]->store(definer_buffer.str, definer_buffer.length, cs); + table->field[19]->store(trigger->client_cs_name.str, + trigger->client_cs_name.length, cs); + table->field[20]->store(trigger->connection_cl_name.str, + trigger->connection_cl_name.length, cs); + table->field[21]->store(trigger->db_cl_name.str, + trigger->db_cl_name.length, cs); return schema_table_store_record(thd, table); } @@ -6458,35 +6485,16 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, { for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++) { - LEX_STRING trigger_name; - LEX_STRING trigger_stmt; - ulong sql_mode; - char definer_holder[USER_HOST_BUFF_SIZE]; - LEX_STRING definer_buffer; - LEX_STRING client_cs_name; - LEX_STRING connection_cl_name; - LEX_STRING db_cl_name; - - definer_buffer.str= definer_holder; - if (triggers->get_trigger_info(thd, (enum trg_event_type) event, - (enum trg_action_time_type)timing, - &trigger_name, &trigger_stmt, - &sql_mode, - &definer_buffer, - &client_cs_name, - &connection_cl_name, - &db_cl_name)) - continue; - - if (store_trigger(thd, table, db_name, table_name, &trigger_name, - (enum trg_event_type) event, - (enum trg_action_time_type) timing, &trigger_stmt, - sql_mode, - &definer_buffer, - &client_cs_name, - &connection_cl_name, - &db_cl_name)) - DBUG_RETURN(1); + Trigger *trigger; + for (trigger= triggers-> + get_trigger((enum trg_event_type) event, + (enum trg_action_time_type) timing) ; + trigger; + trigger= trigger->next) + { + if (store_trigger(thd, trigger, table, db_name, table_name)) + DBUG_RETURN(1); + } } } } @@ -7569,6 +7577,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) strlen(fields_info->field_name), fields_info->field_type))) DBUG_RETURN(0); + item->decimals= fields_info->field_length; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: @@ -8776,7 +8785,8 @@ ST_FIELD_INFO triggers_fields_info[]= OPEN_FRM_ONLY}, {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY}, - {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY}, + /* 2 here indicates 2 decimals */ + {"CREATED", 2, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY}, {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY}, {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY}, {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, @@ -9307,35 +9317,35 @@ int finalize_schema_table(st_plugin_int *plugin) DBUG_RETURN(0); } +/* + This is used to create a timestamp field +*/ + +MYSQL_TIME zero_time={ 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_TIME }; /** Output trigger information (SHOW CREATE TRIGGER) to the client. @param thd Thread context. - @param triggers List of triggers for the table. - @param trigger_idx Index of the trigger to dump. + @param trigger Trigger to dump @return Operation status @retval TRUE Error. @retval FALSE Success. */ -static bool show_create_trigger_impl(THD *thd, - Table_triggers_list *triggers, - int trigger_idx) +static bool show_create_trigger_impl(THD *thd, Trigger *trigger) { int ret_code; Protocol *p= thd->protocol; List fields; - LEX_STRING trg_name; - ulonglong trg_sql_mode; - LEX_STRING trg_sql_mode_str; + LEX_STRING trg_sql_mode_str, trg_body; LEX_STRING trg_sql_original_stmt; - LEX_STRING trg_client_cs_name; - LEX_STRING trg_connection_cl_name; - LEX_STRING trg_db_cl_name; + LEX_STRING trg_definer; CHARSET_INFO *trg_client_cs; MEM_ROOT *mem_root= thd->mem_root; + char definer_holder[USER_HOST_BUFF_SIZE]; + trg_definer.str= definer_holder; /* TODO: Check privileges here. This functionality will be added by @@ -9349,20 +9359,12 @@ static bool show_create_trigger_impl(THD *thd, /* Prepare trigger "object". */ - triggers->get_trigger_info(thd, - trigger_idx, - &trg_name, - &trg_sql_mode, - &trg_sql_original_stmt, - &trg_client_cs_name, - &trg_connection_cl_name, - &trg_db_cl_name); - - sql_mode_string_representation(thd, trg_sql_mode, &trg_sql_mode_str); + trigger->get_trigger_info(&trg_sql_original_stmt, &trg_body, &trg_definer); + sql_mode_string_representation(thd, trigger->sql_mode, &trg_sql_mode_str); /* Resolve trigger client character set. */ - if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs)) + if (resolve_charset(trigger->client_cs_name.str, NULL, &trg_client_cs)) return TRUE; /* Send header. */ @@ -9404,6 +9406,11 @@ static bool show_create_trigger_impl(THD *thd, MY_CS_NAME_SIZE), mem_root); + Item_datetime_literal *tmp= (new (mem_root) + Item_datetime_literal(thd, &zero_time, 2)); + tmp->set_name(thd, STRING_WITH_LEN("Created"), system_charset_info); + fields.push_back(tmp, mem_root); + if (p->send_result_set_metadata(&fields, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -9413,8 +9420,8 @@ static bool show_create_trigger_impl(THD *thd, p->prepare_for_resend(); - p->store(trg_name.str, - trg_name.length, + p->store(trigger->name.str, + trigger->name.length, system_charset_info); p->store(trg_sql_mode_str.str, @@ -9425,18 +9432,30 @@ static bool show_create_trigger_impl(THD *thd, trg_sql_original_stmt.length, trg_client_cs); - p->store(trg_client_cs_name.str, - trg_client_cs_name.length, + p->store(trigger->client_cs_name.str, + trigger->client_cs_name.length, system_charset_info); - p->store(trg_connection_cl_name.str, - trg_connection_cl_name.length, + p->store(trigger->connection_cl_name.str, + trigger->connection_cl_name.length, system_charset_info); - p->store(trg_db_cl_name.str, - trg_db_cl_name.length, + p->store(trigger->db_cl_name.str, + trigger->db_cl_name.length, system_charset_info); + if (trigger->create_time) + { + MYSQL_TIME timestamp; + thd->variables.time_zone->gmt_sec_to_TIME(×tamp, + trigger->create_time/100); + timestamp.second_part= (trigger->create_time % 100) * 10000; + p->store(×tamp, 2); + } + else + p->store_null(); + + ret_code= p->write(); if (!ret_code) @@ -9528,7 +9547,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) TABLE_LIST *lst= get_trigger_table(thd, trg_name); uint num_tables; /* NOTE: unused, only to pass to open_tables(). */ Table_triggers_list *triggers; - int trigger_idx; + Trigger *trigger; bool error= TRUE; if (!lst) @@ -9569,9 +9588,9 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) goto exit; } - trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name); + trigger= triggers->find_trigger(&trg_name->m_name, 0); - if (trigger_idx < 0) + if (!trigger) { my_error(ER_TRG_CORRUPTED_FILE, MYF(0), (const char *) trg_name->m_db.str, @@ -9580,7 +9599,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) goto exit; } - error= show_create_trigger_impl(thd, triggers, trigger_idx); + error= show_create_trigger_impl(thd, trigger); /* NOTE: if show_create_trigger_impl() failed, that means we could not diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 5213c21e8a2..d3954d0ee73 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -34,30 +34,17 @@ #include "sp_cache.h" // sp_invalidate_cache #include -/*************************************************************************/ - -template -inline T *alloc_type(MEM_ROOT *m) +LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, uint length, + MEM_ROOT *mem_root) { - return (T *) alloc_root(m, sizeof (T)); -} - -/* - NOTE: Since alloc_type() is declared as inline, alloc_root() calls should - be inlined by the compiler. So, implementation of alloc_root() is not - needed. However, let's put the implementation in object file just in case - of stupid MS or other old compilers. -*/ - -template LEX_STRING *alloc_type(MEM_ROOT *m); -template ulonglong *alloc_type(MEM_ROOT *m); - -inline LEX_STRING *alloc_lex_string(MEM_ROOT *m) -{ - return alloc_type(m); + if (!(lex_str->str= strmake_root(mem_root, str, length))) + return 0; + lex_str->length= length; + return lex_str; } /*************************************************************************/ + /** Trigger_creation_ctx -- creation context of triggers. */ @@ -73,7 +60,12 @@ public: const LEX_STRING *connection_cl_name, const LEX_STRING *db_cl_name); -public: + Trigger_creation_ctx(CHARSET_INFO *client_cs, + CHARSET_INFO *connection_cl, + CHARSET_INFO *db_cl) + :Stored_program_creation_ctx(client_cs, connection_cl, db_cl) + { } + virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root) { return new (mem_root) Trigger_creation_ctx(m_client_cs, @@ -87,16 +79,9 @@ protected: return new Trigger_creation_ctx(thd); } -private: Trigger_creation_ctx(THD *thd) :Stored_program_creation_ctx(thd) { } - - Trigger_creation_ctx(CHARSET_INFO *client_cs, - CHARSET_INFO *connection_cl, - CHARSET_INFO *db_cl) - :Stored_program_creation_ctx(client_cs, connection_cl, db_cl) - { } }; /************************************************************************** @@ -220,6 +205,11 @@ static File_option triggers_file_parameters[]= my_offsetof(class Table_triggers_list, db_cl_names), FILE_OPTIONS_STRLIST }, + { + { C_STRING_WITH_LEN("created") }, + my_offsetof(class Table_triggers_list, create_times), + FILE_OPTIONS_ULLLIST + }, { { 0, 0 }, 0, FILE_OPTIONS_STRING } }; @@ -234,9 +224,12 @@ File_option sql_modes_parameters= This must be kept up to date whenever a new option is added to the list above, as it specifies the number of required parameters of the trigger in .trg file. + This defines the maximum number of parameters that is read. If there are + more paramaters in the file they are ignored. Less number of parameters + is regarded as ok. */ -static const int TRG_NUM_REQUIRED_PARAMETERS= 6; +static const int TRG_NUM_REQUIRED_PARAMETERS= 7; /* Structure representing contents of .TRN file which are used to support @@ -315,7 +308,7 @@ private: Also, if possible, grabs name of the trigger being parsed so it can be used to correctly drop problematic trigger. */ -class Deprecated_trigger_syntax_handler : public Internal_error_handler +class Deprecated_trigger_syntax_handler : public Internal_error_handler { private: @@ -355,6 +348,38 @@ public: }; +Trigger::~Trigger() +{ + delete body; +} + + +/** + Call a Table_triggers_list function for all triggers + + @return 0 ok + @return # Something went wrong. Pointer to the trigger that mailfuncted + returned +*/ + +Trigger* Table_triggers_list::for_all_triggers(Triggers_processor func, + void *arg) +{ + for (uint i= 0; i < (uint)TRG_EVENT_MAX; i++) + { + for (uint j= 0; j < (uint)TRG_ACTION_MAX; j++) + { + for (Trigger *trigger= get_trigger(i,j) ; + trigger ; + trigger= trigger->next) + if ((trigger->*func)(arg)) + return trigger; + } + } + return 0; +} + + /** Create or drop trigger for table. @@ -378,6 +403,7 @@ public: @retval TRUE error */ + bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { /* @@ -393,7 +419,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) bool lock_upgrade_done= FALSE; MDL_ticket *mdl_ticket= NULL; Query_tables_list backup; - DBUG_ENTER("mysql_create_or_drop_trigger"); /* Charset of the buffer for statement must be system one. */ @@ -517,7 +542,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) tables->required_type= FRMTYPE_TABLE; /* Also prevent DROP TRIGGER from opening temporary table which might - shadow base table on which trigger to be dropped is defined. + shadow the subject table on which trigger to be dropped is defined. */ tables->open_type= OT_BASE_ONLY; @@ -586,9 +611,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) end: if (!result) - { result= write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length()); - } /* If we are under LOCK TABLES we should restore original state of @@ -609,8 +632,8 @@ end: } /** - Build stmt_query to write it in the bin-log - and get the trigger definer. + Build stmt_query to write it in the bin-log, the statement to write in + the trigger file and the trigger definer. @param thd current thread context (including trigger definition in LEX) @@ -618,7 +641,8 @@ end: trigger is created. @param[out] stmt_query after successful return, this string contains well-formed statement for creation this trigger. - + @param[out] trigger_def query to be stored in trigger file. As stmt_query, + but without "OR REPLACE" and no FOLLOWS/PRECEDES. @param[out] trg_definer The triggger definer. @param[out] trg_definer_holder Used as a buffer for definer. @@ -630,12 +654,16 @@ end: simultaneously NULL-strings (non-SUID/old trigger) or valid strings (SUID/new trigger). */ + static void build_trig_stmt_query(THD *thd, TABLE_LIST *tables, - String *stmt_query, + String *stmt_query, String *trigger_def, LEX_STRING *trg_definer, char trg_definer_holder[]) { + LEX_STRING stmt_definition; LEX *lex= thd->lex; + uint prefix_trimmed, suffix_trimmed; + size_t original_length; /* Create a query with the full trigger definition. @@ -643,6 +671,8 @@ static void build_trig_stmt_query(THD *thd, TABLE_LIST *tables, */ stmt_query->append(STRING_WITH_LEN("CREATE ")); + trigger_def->copy(*stmt_query); + if (lex->create_info.or_replace()) stmt_query->append(STRING_WITH_LEN("OR REPLACE ")); @@ -651,18 +681,42 @@ static void build_trig_stmt_query(THD *thd, TABLE_LIST *tables, /* SUID trigger */ lex->definer->set_lex_string(trg_definer, trg_definer_holder); append_definer(thd, stmt_query, &lex->definer->user, &lex->definer->host); + append_definer(thd, trigger_def, &lex->definer->user, &lex->definer->host); } else { *trg_definer= empty_lex_str; } - LEX_STRING stmt_definition; - stmt_definition.str= (char*) thd->lex->stmt_definition_begin; - stmt_definition.length= thd->lex->stmt_definition_end - - thd->lex->stmt_definition_begin; - trim_whitespace(thd->charset(), &stmt_definition); + + /* Create statement for binary logging */ + stmt_definition.str= (char*) lex->stmt_definition_begin; + stmt_definition.length= (lex->stmt_definition_end - + lex->stmt_definition_begin); + original_length= stmt_definition.length; + trim_whitespace(thd->charset(), &stmt_definition, &prefix_trimmed); + suffix_trimmed= original_length - stmt_definition.length - prefix_trimmed; + stmt_query->append(stmt_definition.str, stmt_definition.length); + + /* Create statement for storing trigger (without trigger order) */ + if (lex->trg_chistics.ordering_clause == TRG_ORDER_NONE) + trigger_def->append(stmt_definition.str, stmt_definition.length); + else + { + /* Copy data before FOLLOWS/PRECEDES trigger_name */ + trigger_def->append(stmt_definition.str, + (lex->trg_chistics.ordering_clause_begin - + lex->stmt_definition_begin) - prefix_trimmed); + /* Copy data after FOLLOWS/PRECEDES trigger_name */ + trigger_def->append(stmt_definition.str + + (lex->trg_chistics.ordering_clause_end - + lex->stmt_definition_begin) + - prefix_trimmed, + (lex->stmt_definition_end - + lex->trg_chistics.ordering_clause_end) - + suffix_trimmed); + } } @@ -689,6 +743,7 @@ static void build_trig_stmt_query(THD *thd, TABLE_LIST *tables, @retval True error */ + bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, String *stmt_query) { @@ -696,51 +751,27 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, TABLE *table= tables->table; char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN]; LEX_STRING file, trigname_file; - LEX_STRING *trg_def; - ulonglong *trg_sql_mode; char trg_definer_holder[USER_HOST_BUFF_SIZE]; - LEX_STRING *trg_definer; Item_trigger_field *trg_field; struct st_trigname trigname; - LEX_STRING *trg_client_cs_name; - LEX_STRING *trg_connection_cl_name; - LEX_STRING *trg_db_cl_name; - sp_head *trg_body= bodies[lex->trg_chistics.event] - [lex->trg_chistics.action_time]; + String trigger_definition; + Trigger *trigger= 0; + bool trigger_dropped= 0; + DBUG_ENTER("create_trigger"); if (check_for_broken_triggers()) - return true; + DBUG_RETURN(true); /* Trigger must be in the same schema as target table. */ if (my_strcasecmp(table_alias_charset, table->s->db.str, lex->spname->m_db.str)) { my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); - return true; - } - - /* - We don't allow creation of several triggers of the same type yet. - If a trigger with the same type already exists: - a. Throw a ER_NOT_SUPPORTED_YET error, - if the old and the new trigger names are different; - b. Or continue, if the old and the new trigger names are the same: - - either to recreate the trigger on "CREATE OR REPLACE" - - or send a "already exists" warning on "CREATE IF NOT EXISTS" - - or send an "alredy exists" error on normal CREATE. - */ - if (trg_body != 0 && - my_strcasecmp(table_alias_charset, - trg_body->m_name.str, lex->spname->m_name.str)) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "multiple triggers with the same action time" - " and event for one table"); - return true; + DBUG_RETURN(true); } if (sp_process_definer(thd)) - return true; + DBUG_RETURN(true); /* Let us check if all references to fields in old/new versions of row in @@ -769,7 +800,20 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, if (!trg_field->fixed && trg_field->fix_fields(thd, (Item **)0)) - return true; + DBUG_RETURN(true); + } + + /* Ensure anchor trigger exists */ + if (lex->trg_chistics.ordering_clause != TRG_ORDER_NONE) + { + if (!(trigger= find_trigger(&lex->trg_chistics.anchor_trigger_name, 0)) || + trigger->event != lex->trg_chistics.event || + trigger->action_time != lex->trg_chistics.action_time) + { + my_error(ER_REFERENCED_TRG_DOES_NOT_EXIST, MYF(0), + lex->trg_chistics.anchor_trigger_name.str); + DBUG_RETURN(true); + } } /* @@ -793,10 +837,13 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, if (lex->create_info.or_replace()) { String drop_trg_query; - drop_trg_query.append("DROP TRIGGER "); - drop_trg_query.append(lex->spname->m_name.str); - if (drop_trigger(thd, tables, &drop_trg_query)) - return 1; + /* + The following can fail if the trigger is for another table or + there exists a .TRN file but there was no trigger for it in + the .TRG file + */ + if (unlikely(drop_trigger(thd, tables, &drop_trg_query))) + DBUG_RETURN(true); } else if (lex->create_info.if_not_exists()) { @@ -805,54 +852,48 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ER_THD(thd, ER_TRG_ALREADY_EXISTS), trigname_buff); LEX_STRING trg_definer_tmp; - build_trig_stmt_query(thd, tables, stmt_query, + String trigger_def; + + /* + Log query with IF NOT EXISTS to binary log. This is in line with + CREATE TABLE IF NOT EXISTS. + */ + build_trig_stmt_query(thd, tables, stmt_query, &trigger_def, &trg_definer_tmp, trg_definer_holder); - return false; + DBUG_RETURN(false); } else { my_error(ER_TRG_ALREADY_EXISTS, MYF(0)); - return true; + DBUG_RETURN(true); } } trigname.trigger_table.str= tables->table_name; trigname.trigger_table.length= tables->table_name_length; + /* + We are not using lex->sphead here as an argument to Trigger() as we are + going to access lex->sphead later in build_trig_stmt_query() + */ + if (!(trigger= new (&table->mem_root) Trigger(this, 0))) + goto err_without_cleanup; + + /* Create trigger_name.TRN file to ensure trigger name is unique */ if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type, (uchar*)&trigname, trigname_file_parameters)) - return true; + goto err_without_cleanup; - /* - Soon we will invalidate table object and thus Table_triggers_list object - so don't care about place to which trg_def->ptr points and other - invariants (e.g. we don't bother to update names_list) + /* Populate the trigger object */ - QQ: Hmm... probably we should not care about setting up active thread - mem_root too. - */ - if (!(trg_def= alloc_lex_string(&table->mem_root)) || - definitions_list.push_back(trg_def, &table->mem_root) || + trigger->sql_mode= thd->variables.sql_mode; + /* Time with 2 decimals, like in MySQL 5.7 */ + trigger->create_time= ((ulonglong) thd->query_start())*100 + thd->query_start_sec_part()/10000; + build_trig_stmt_query(thd, tables, stmt_query, &trigger_definition, + &trigger->definer, trg_definer_holder); - !(trg_sql_mode= alloc_type(&table->mem_root)) || - definition_modes_list.push_back(trg_sql_mode, &table->mem_root) || - - !(trg_definer= alloc_lex_string(&table->mem_root)) || - definers_list.push_back(trg_definer, &table->mem_root) || - - !(trg_client_cs_name= alloc_lex_string(&table->mem_root)) || - client_cs_names.push_back(trg_client_cs_name, &table->mem_root) || - - !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) || - connection_cl_names.push_back(trg_connection_cl_name, &table->mem_root) || - - !(trg_db_cl_name= alloc_lex_string(&table->mem_root)) || - db_cl_names.push_back(trg_db_cl_name, &table->mem_root)) - { - goto err_with_cleanup; - } - - *trg_sql_mode= thd->variables.sql_mode; + trigger->definition.str= trigger_definition.c_ptr(); + trigger->definition.length= trigger_definition.length(); /* Fill character set information: @@ -860,33 +901,104 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, - connection collation contains pair {character set, collation}; - database collation contains pair {character set, collation}; */ - - lex_string_set(trg_client_cs_name, thd->charset()->csname); - - lex_string_set(trg_connection_cl_name, + lex_string_set(&trigger->client_cs_name, thd->charset()->csname); + lex_string_set(&trigger->connection_cl_name, thd->variables.collation_connection->name); - - lex_string_set(trg_db_cl_name, + lex_string_set(&trigger->db_cl_name, get_default_db_collation(thd, tables->db)->name); - build_trig_stmt_query(thd, tables, stmt_query, - trg_definer, trg_definer_holder); + /* Add trigger in it's correct place */ + add_trigger(lex->trg_chistics.event, + lex->trg_chistics.action_time, + lex->trg_chistics.ordering_clause, + &lex->trg_chistics.anchor_trigger_name, + trigger); - trg_def->str= stmt_query->c_ptr_safe(); - trg_def->length= stmt_query->length(); - - /* Create trigger definition file. */ + /* Create trigger definition file .TRG */ + if (unlikely(create_lists_needed_for_files(thd->mem_root))) + goto err_with_cleanup; if (!sql_create_definition_file(NULL, &file, &triggers_file_type, (uchar*)this, triggers_file_parameters)) - return false; + DBUG_RETURN(false); err_with_cleanup: + /* Delete .TRN file */ mysql_file_delete(key_file_trn, trigname_buff, MYF(MY_WME)); - return true; + +err_without_cleanup: + delete trigger; // Safety, not critical + + if (trigger_dropped) + { + String drop_trg_query; + drop_trg_query.append("DROP TRIGGER /* generated by failed CREATE TRIGGER */ "); + drop_trg_query.append(lex->spname->m_name.str); + /* + We dropped an existing trigger and was not able to recreate it because + of an internal error. Ensure it's also dropped on the slave. + */ + write_bin_log(thd, FALSE, drop_trg_query.ptr(), drop_trg_query.length()); + } + DBUG_RETURN(true); } +/** + Empty all list used to load and create .TRG file +*/ + +void Table_triggers_list::empty_lists() +{ + definitions_list.empty(); + definition_modes_list.empty(); + definers_list.empty(); + client_cs_names.empty(); + connection_cl_names.empty(); + db_cl_names.empty(); + create_times.empty(); +} + + +/** + Create list of all trigger parameters for sql_create_definition_file() +*/ + +struct create_lists_param +{ + MEM_ROOT *root; +}; + + +bool Table_triggers_list::create_lists_needed_for_files(MEM_ROOT *root) +{ + create_lists_param param; + + empty_lists(); + param.root= root; + + return for_all_triggers(&Trigger::add_to_file_list, ¶m); +} + + +bool Trigger::add_to_file_list(void* param_arg) +{ + create_lists_param *param= (create_lists_param*) param_arg; + MEM_ROOT *mem_root= param->root; + + if (base->definitions_list.push_back(&definition, mem_root) || + base->definition_modes_list.push_back(&sql_mode, mem_root) || + base->definers_list.push_back(&definer, mem_root) || + base->client_cs_names.push_back(&client_cs_name, mem_root) || + base->connection_cl_names.push_back(&connection_cl_name, mem_root) || + base->db_cl_names.push_back(&db_cl_name, mem_root) || + base->create_times.push_back(&create_time, mem_root)) + return 1; + return 0; +} + + + /** Deletes the .TRG file for a table. @@ -944,17 +1056,57 @@ static bool rm_trigname_file(char *path, const char *db, TRUE Error */ -static bool save_trigger_file(Table_triggers_list *triggers, const char *db, - const char *table_name) +bool Table_triggers_list::save_trigger_file(THD *thd, const char *db, + const char *table_name) { char file_buff[FN_REFLEN]; LEX_STRING file; + if (create_lists_needed_for_files(thd->mem_root)) + return true; + file.length= build_table_filename(file_buff, FN_REFLEN - 1, db, table_name, TRG_EXT, 0); file.str= file_buff; return sql_create_definition_file(NULL, &file, &triggers_file_type, - (uchar*)triggers, triggers_file_parameters); + (uchar*) this, triggers_file_parameters); +} + + +/** + Find a trigger with a given name + + @param name Name of trigger + @param remove_from_list If set, remove trigger if found +*/ + +Trigger *Table_triggers_list::find_trigger(const LEX_STRING *name, + bool remove_from_list) +{ + for (uint i= 0; i < (uint)TRG_EVENT_MAX; i++) + { + for (uint j= 0; j < (uint)TRG_ACTION_MAX; j++) + { + Trigger **parent, *trigger; + + for (parent= &triggers[i][j]; + (trigger= *parent); + parent= &trigger->next) + { + if (my_strcasecmp(table_alias_charset, + trigger->name.str, name->str) == 0) + { + if (remove_from_list) + { + *parent= trigger->next; + count--; + } + return trigger; + } + } + } + } + return 0; } @@ -979,85 +1131,70 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db, @retval True error */ + bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables, String *stmt_query) { - const char *sp_name= thd->lex->spname->m_name.str; // alias - - LEX_STRING *name; + const LEX_STRING *sp_name= &thd->lex->spname->m_name; // alias char path[FN_REFLEN]; + Trigger *trigger; - List_iterator_fast it_name(names_list); + stmt_query->set(thd->query(), thd->query_length(), stmt_query->charset()); - List_iterator it_mod(definition_modes_list); - List_iterator it_def(definitions_list); - List_iterator it_definer(definers_list); - List_iterator it_client_cs_name(client_cs_names); - List_iterator it_connection_cl_name(connection_cl_names); - List_iterator it_db_cl_name(db_cl_names); - - stmt_query->append(thd->query(), thd->query_length()); - - while ((name= it_name++)) + /* Find and delete trigger from list */ + if (!(trigger= find_trigger(sp_name, true))) { - it_def++; - it_mod++; - it_definer++; - it_client_cs_name++; - it_connection_cl_name++; - it_db_cl_name++; - - if (my_strcasecmp(table_alias_charset, sp_name, name->str) == 0) - { - /* - Again we don't care much about other things required for - clean trigger removing since table will be reopened anyway. - */ - it_def.remove(); - it_mod.remove(); - it_definer.remove(); - it_client_cs_name.remove(); - it_connection_cl_name.remove(); - it_db_cl_name.remove(); - - if (definitions_list.is_empty()) - { - /* - TODO: Probably instead of removing .TRG file we should move - to archive directory but this should be done as part of - parse_file.cc functionality (because we will need it - elsewhere). - */ - if (rm_trigger_file(path, tables->db, tables->table_name)) - return 1; - } - else - { - if (save_trigger_file(this, tables->db, tables->table_name)) - return 1; - } - - if (rm_trigname_file(path, tables->db, sp_name)) - return 1; - return 0; - } + my_message(ER_TRG_DOES_NOT_EXIST, ER_THD(thd, ER_TRG_DOES_NOT_EXIST), + MYF(0)); + return 1; } - my_message(ER_TRG_DOES_NOT_EXIST, ER_THD(thd, ER_TRG_DOES_NOT_EXIST), - MYF(0)); - return 1; + if (!count) // If no more triggers + { + /* + TODO: Probably instead of removing .TRG file we should move + to archive directory but this should be done as part of + parse_file.cc functionality (because we will need it + elsewhere). + */ + if (rm_trigger_file(path, tables->db, tables->table_name)) + return 1; + } + else + { + if (save_trigger_file(thd, tables->db, tables->table_name)) + return 1; + } + + if (rm_trigname_file(path, tables->db, sp_name->str)) + return 1; + + delete trigger; + return 0; } Table_triggers_list::~Table_triggers_list() { - for (int i= 0; i < (int)TRG_EVENT_MAX; i++) - for (int j= 0; j < (int)TRG_ACTION_MAX; j++) - delete bodies[i][j]; + DBUG_ENTER("Table_triggers_list::~Table_triggers_list"); + for (uint i= 0; i < (uint)TRG_EVENT_MAX; i++) + { + for (uint j= 0; j < (uint)TRG_ACTION_MAX; j++) + { + Trigger *next, *trigger; + for (trigger= get_trigger(i,j) ; trigger ; trigger= next) + { + next= trigger->next; + delete trigger; + } + } + } if (record1_field) for (Field **fld_ptr= record1_field; *fld_ptr; fld_ptr++) delete *fld_ptr; + + DBUG_VOID_RETURN; } @@ -1073,13 +1210,14 @@ Table_triggers_list::~Table_triggers_list() @retval True error */ + bool Table_triggers_list::prepare_record_accessors(TABLE *table) { Field **fld, **trg_fld; - if ((bodies[TRG_EVENT_INSERT][TRG_ACTION_BEFORE] || - bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]) - && (table->s->stored_fields != table->s->null_fields)) + if ((has_triggers(TRG_EVENT_INSERT,TRG_ACTION_BEFORE) || + has_triggers(TRG_EVENT_UPDATE,TRG_ACTION_BEFORE)) && + (table->s->stored_fields != table->s->null_fields)) { int null_bytes= (table->s->stored_fields - table->s->null_fields + 7)/8; @@ -1119,10 +1257,10 @@ bool Table_triggers_list::prepare_record_accessors(TABLE *table) else record0_field= table->field; - if (bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE] || - bodies[TRG_EVENT_UPDATE][TRG_ACTION_AFTER] || - bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] || - bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]) + if (has_triggers(TRG_EVENT_UPDATE,TRG_ACTION_BEFORE) || + has_triggers(TRG_EVENT_UPDATE,TRG_ACTION_AFTER) || + has_triggers(TRG_EVENT_DELETE,TRG_ACTION_BEFORE) || + has_triggers(TRG_EVENT_DELETE,TRG_ACTION_AFTER)) { if (!(record1_field= (Field **)alloc_root(&table->mem_root, (table->s->fields + 1) * @@ -1173,7 +1311,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, LEX_STRING path; File_parser *parser; LEX_STRING save_db; - DBUG_ENTER("Table_triggers_list::check_n_load"); path.length= build_table_filename(path_buff, FN_REFLEN - 1, @@ -1184,194 +1321,54 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, if (access(path_buff, F_OK)) DBUG_RETURN(0); - /* - File exists so we got to load triggers. - FIXME: A lot of things to do here e.g. how about other funcs and being - more paranoical ? - */ + /* File exists so we got to load triggers */ if ((parser= sql_parse_prepare(&path, &table->mem_root, 1))) { if (is_equal(&triggers_file_type, parser->type())) { - Table_triggers_list *triggers= - new (&table->mem_root) Table_triggers_list(table); Handle_old_incorrect_sql_modes_hook sql_modes_hook(path.str); + LEX_STRING *trg_create_str; + ulonglong *trg_sql_mode, *trg_create_time; + Trigger *trigger; + Table_triggers_list *trigger_list= + new (&table->mem_root) Table_triggers_list(table); + if (unlikely(!trigger_list)) + goto error; - if (!triggers) - DBUG_RETURN(1); - - /* - We don't have the following attributes in old versions of .TRG file, so - we should initialize the list for safety: - - sql_modes; - - definers; - - character sets (client, connection, database); - */ - triggers->definition_modes_list.empty(); - triggers->definers_list.empty(); - triggers->client_cs_names.empty(); - triggers->connection_cl_names.empty(); - triggers->db_cl_names.empty(); - - if (parser->parse((uchar*)triggers, &table->mem_root, + if (parser->parse((uchar*)trigger_list, &table->mem_root, triggers_file_parameters, TRG_NUM_REQUIRED_PARAMETERS, &sql_modes_hook)) - DBUG_RETURN(1); + goto error; - List_iterator_fast it(triggers->definitions_list); - LEX_STRING *trg_create_str; - ulonglong *trg_sql_mode; + List_iterator_fast it(trigger_list->definitions_list); - if (triggers->definition_modes_list.is_empty() && - !triggers->definitions_list.is_empty()) + if (!trigger_list->definitions_list.is_empty() && + (trigger_list->client_cs_names.is_empty() || + trigger_list->connection_cl_names.is_empty() || + trigger_list->db_cl_names.is_empty())) { - /* - It is old file format => we should fill list of sql_modes. - - We use one mode (current) for all triggers, because we have not - information about mode in old format. - */ - if (!(trg_sql_mode= alloc_type(&table->mem_root))) - { - DBUG_RETURN(1); // EOM - } - *trg_sql_mode= global_system_variables.sql_mode; - while (it++) - { - if (triggers->definition_modes_list.push_back(trg_sql_mode, - &table->mem_root)) - { - DBUG_RETURN(1); // EOM - } - } - it.rewind(); - } - - if (triggers->definers_list.is_empty() && - !triggers->definitions_list.is_empty()) - { - /* - It is old file format => we should fill list of definers. - - If there is no definer information, we should not switch context to - definer when checking privileges. I.e. privileges for such triggers - are checked for "invoker" rather than for "definer". - */ - - LEX_STRING *trg_definer; - - if (!(trg_definer= alloc_lex_string(&table->mem_root))) - DBUG_RETURN(1); // EOM - - trg_definer->str= (char*) ""; - trg_definer->length= 0; - - while (it++) - { - if (triggers->definers_list.push_back(trg_definer, - &table->mem_root)) - { - DBUG_RETURN(1); // EOM - } - } - - it.rewind(); - } - - if (!triggers->definitions_list.is_empty() && - (triggers->client_cs_names.is_empty() || - triggers->connection_cl_names.is_empty() || - triggers->db_cl_names.is_empty())) - { - /* - It is old file format => we should fill lists of character sets. - */ - - LEX_STRING *trg_client_cs_name; - LEX_STRING *trg_connection_cl_name; - LEX_STRING *trg_db_cl_name; - - if (!triggers->client_cs_names.is_empty() || - !triggers->connection_cl_names.is_empty() || - !triggers->db_cl_names.is_empty()) - { - my_error(ER_TRG_CORRUPTED_FILE, MYF(0), - (const char *) db, - (const char *) table_name); - - DBUG_RETURN(1); // EOM - } - + /* We will later use the current character sets */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_TRG_NO_CREATION_CTX, ER_THD(thd, ER_TRG_NO_CREATION_CTX), (const char*) db, (const char*) table_name); - - if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) || - !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) || - !(trg_db_cl_name= alloc_lex_string(&table->mem_root))) - { - DBUG_RETURN(1); // EOM - } - - /* - Backward compatibility: assume that the query is in the current - character set. - */ - - lex_string_set(trg_client_cs_name, - thd->variables.character_set_client->csname); - - lex_string_set(trg_connection_cl_name, - thd->variables.collation_connection->name); - - lex_string_set(trg_db_cl_name, - thd->variables.collation_database->name); - - while (it++) - { - if (triggers->client_cs_names.push_back(trg_client_cs_name, - &table->mem_root) || - - triggers->connection_cl_names.push_back(trg_connection_cl_name, - &table->mem_root) || - - triggers->db_cl_names.push_back(trg_db_cl_name, - &table->mem_root)) - { - DBUG_RETURN(1); // EOM - } - } - - it.rewind(); } - DBUG_ASSERT(triggers->definition_modes_list.elements == - triggers->definitions_list.elements); - DBUG_ASSERT(triggers->definers_list.elements == - triggers->definitions_list.elements); - DBUG_ASSERT(triggers->client_cs_names.elements == - triggers->definitions_list.elements); - DBUG_ASSERT(triggers->connection_cl_names.elements == - triggers->definitions_list.elements); - DBUG_ASSERT(triggers->db_cl_names.elements == - triggers->definitions_list.elements); - - table->triggers= triggers; + table->triggers= trigger_list; status_var_increment(thd->status_var.feature_trigger); - List_iterator_fast itm(triggers->definition_modes_list); - List_iterator_fast it_definer(triggers->definers_list); - List_iterator_fast it_client_cs_name(triggers->client_cs_names); - List_iterator_fast it_connection_cl_name(triggers->connection_cl_names); - List_iterator_fast it_db_cl_name(triggers->db_cl_names); + List_iterator_fast itm(trigger_list->definition_modes_list); + List_iterator_fast it_definer(trigger_list->definers_list); + List_iterator_fast it_client_cs_name(trigger_list->client_cs_names); + List_iterator_fast it_connection_cl_name(trigger_list->connection_cl_names); + List_iterator_fast it_db_cl_name(trigger_list->db_cl_names); + List_iterator_fast it_create_times(trigger_list->create_times); LEX *old_lex= thd->lex, lex; sp_rcontext *save_spcont= thd->spcont; - ulonglong save_sql_mode= thd->variables.sql_mode; - LEX_STRING *on_table_name; + sql_mode_t save_sql_mode= thd->variables.sql_mode; thd->lex= &lex; @@ -1381,30 +1378,55 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, while ((trg_create_str= it++)) { sp_head *sp; - trg_sql_mode= itm++; - LEX_STRING *trg_definer= it_definer++; + sql_mode_t sql_mode; + LEX_STRING *trg_definer; + Trigger_creation_ctx *creation_ctx; - thd->variables.sql_mode= (ulong)*trg_sql_mode; + /* + It is old file format then sql_mode may not be filled in. + We use one mode (current) for all triggers, because we have not + information about mode in old format. + */ + sql_mode= ((trg_sql_mode= itm++) ? *trg_sql_mode : + global_system_variables.sql_mode); + + trg_create_time= it_create_times++; // May be NULL if old file + trg_definer= it_definer++; // May be NULL if old file + + thd->variables.sql_mode= sql_mode; Parser_state parser_state; if (parser_state.init(thd, trg_create_str->str, trg_create_str->length)) goto err_with_lex_cleanup; - Trigger_creation_ctx *creation_ctx= - Trigger_creation_ctx::create(thd, - db, - table_name, - it_client_cs_name++, - it_connection_cl_name++, - it_db_cl_name++); + if (!trigger_list->client_cs_names.is_empty()) + creation_ctx= Trigger_creation_ctx::create(thd, + db, + table_name, + it_client_cs_name++, + it_connection_cl_name++, + it_db_cl_name++); + else + { + /* Old file with not stored character sets. Use current */ + creation_ctx= new + Trigger_creation_ctx(thd->variables.character_set_client, + thd->variables.collation_connection, + thd->variables.collation_database); + } lex_start(thd); thd->spcont= NULL; + /* The following is for catching parse errors */ + lex.trg_chistics.event= TRG_EVENT_MAX; + lex.trg_chistics.action_time= TRG_ACTION_MAX; Deprecated_trigger_syntax_handler error_handler; thd->push_internal_handler(&error_handler); + bool parse_error= parse_sql(thd, & parser_state, creation_ctx); thd->pop_internal_handler(); + DBUG_ASSERT(!parse_error || lex.sphead == 0); /* Not strictly necessary to invoke this method here, since we know @@ -1416,68 +1438,73 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, */ lex.set_trg_event_type_for_tables(); + if (lex.sphead) + lex.sphead->set_info(0, 0, &lex.sp_chistics, sql_mode); + + if (unlikely(!(trigger= (new (&table->mem_root) + Trigger(trigger_list, lex.sphead))))) + goto err_with_lex_cleanup; + lex.sphead= NULL; /* Prevent double cleanup. */ + + sp= trigger->body; + + trigger->sql_mode= sql_mode; + trigger->definition= *trg_create_str; + trigger->create_time= trg_create_time ? *trg_create_time : 0; + trigger->name= sp ? sp->m_name : empty_lex_str; + trigger->on_table_name.str= (char*) lex.raw_trg_on_table_name_begin; + trigger->on_table_name.length= (lex.raw_trg_on_table_name_end - + lex.raw_trg_on_table_name_begin); + + /* Copy pointers to character sets to make trigger easier to use */ + lex_string_set(&trigger->client_cs_name, + creation_ctx->get_client_cs()->csname); + lex_string_set(&trigger->connection_cl_name, + creation_ctx->get_connection_cl()->name); + lex_string_set(&trigger->db_cl_name, + creation_ctx->get_db_cl()->name); + + /* event can only be TRG_EVENT_MAX in case of fatal parse errors */ + if (lex.trg_chistics.event != TRG_EVENT_MAX) + trigger_list->add_trigger(lex.trg_chistics.event, + lex.trg_chistics.action_time, + TRG_ORDER_NONE, + &lex.trg_chistics.anchor_trigger_name, + trigger); + if (parse_error) { - if (!triggers->m_has_unparseable_trigger) - triggers->set_parse_error_message(error_handler.get_error_message()); + LEX_STRING *name; + + /* + In case of errors, disable all triggers for the table, but keep + the wrong trigger around to allow the user to fix it + */ + if (!trigger_list->m_has_unparseable_trigger) + trigger_list->set_parse_error_message(error_handler.get_error_message()); /* Currently sphead is always set to NULL in case of a parse error */ DBUG_ASSERT(lex.sphead == 0); - if (error_handler.get_trigger_name()) - { - LEX_STRING *trigger_name; - const LEX_STRING *orig_trigger_name= error_handler.get_trigger_name(); - - if (!(trigger_name= alloc_lex_string(&table->mem_root)) || - !(trigger_name->str= strmake_root(&table->mem_root, - orig_trigger_name->str, - orig_trigger_name->length))) - goto err_with_lex_cleanup; - - trigger_name->length= orig_trigger_name->length; - - if (triggers->names_list.push_back(trigger_name, - &table->mem_root)) - goto err_with_lex_cleanup; - } - else - { - /* - The Table_triggers_list is not constructed as a list of - trigger objects as one would expect, but rather of lists of - properties of equal length. Thus, even if we don't get the - trigger name, we still fill all in all the lists with - placeholders as we might otherwise create a skew in the - lists. Obviously, this has to be refactored. - */ - LEX_STRING *empty= alloc_lex_string(&table->mem_root); - if (!empty) - goto err_with_lex_cleanup; - - empty->str= const_cast(""); - empty->length= 0; - if (triggers->names_list.push_back(empty, &table->mem_root)) - goto err_with_lex_cleanup; - } lex_end(&lex); + + if ((name= error_handler.get_trigger_name())) + { + if (!(make_lex_string(&trigger->name, name->str, + name->length, &table->mem_root))) + goto err_with_lex_cleanup; + } + trigger->definer= ((!trg_definer || !trg_definer->length) ? + empty_lex_str : *trg_definer); continue; } - lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); - - int event= lex.trg_chistics.event; - int action_time= lex.trg_chistics.action_time; - - sp= triggers->bodies[event][action_time]= lex.sphead; - lex.sphead= NULL; /* Prevent double cleanup. */ - - sp->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); + sp->set_info(0, 0, &lex.sp_chistics, sql_mode); sp->set_creation_ctx(creation_ctx); - if (!trg_definer->length) + if (!trg_definer || !trg_definer->length) { /* This trigger was created/imported from the previous version of - MySQL, which does not support triggers definers. We should emit + MySQL, which does not support trigger_list definers. We should emit warning here. */ @@ -1493,34 +1520,26 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, */ sp->set_definer((char*) "", 0); + trigger->definer= empty_lex_str; /* - Triggers without definer information are executed under the + trigger_list without definer information are executed under the authorization of the invoker. */ sp->m_chistics->suid= SP_IS_NOT_SUID; } else + { sp->set_definer(trg_definer->str, trg_definer->length); + trigger->definer= *trg_definer; + } - if (triggers->names_list.push_back(&sp->m_name, &table->mem_root)) - goto err_with_lex_cleanup; - - if (!(on_table_name= alloc_lex_string(&table->mem_root))) - goto err_with_lex_cleanup; - - on_table_name->str= (char*) lex.raw_trg_on_table_name_begin; - on_table_name->length= lex.raw_trg_on_table_name_end - - lex.raw_trg_on_table_name_begin; - - if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root)) - goto err_with_lex_cleanup; #ifndef DBUG_OFF /* Let us check that we correctly update trigger definitions when we - rename tables with triggers. - + rename tables with trigger_list. + In special cases like "RENAME TABLE `#mysql50#somename` TO `somename`" or "ALTER DATABASE `#mysql50#somename` UPGRADE DATA DIRECTORY NAME" we might be given table or database name with "#mysql50#" prefix (and @@ -1545,11 +1564,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, /* Gather all Item_trigger_field objects representing access to fields in old/new versions of row in trigger into lists containing all such - objects for the triggers with same action and timing. + objects for the trigger_list with same action and timing. */ - triggers->trigger_fields[lex.trg_chistics.event] - [lex.trg_chistics.action_time]= - lex.trg_table_fields.first; + trigger->trigger_fields= lex.trg_table_fields.first; /* Also let us bind these objects to Field objects in table being opened. @@ -1564,8 +1581,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, trg_field= trg_field->next_trg_field) { trg_field->setup_field(thd, table, - &triggers->subject_table_grants[lex.trg_chistics.event] - [lex.trg_chistics.action_time]); + &trigger->subject_table_grants); } lex_end(&lex); @@ -1575,9 +1591,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; - if (!names_only && triggers->prepare_record_accessors(table)) - DBUG_RETURN(1); + if (!names_only && trigger_list->prepare_record_accessors(table)) + goto error; + /* Ensure no one is accidently using the temporary load lists */ + trigger_list->empty_lists(); DBUG_RETURN(0); err_with_lex_cleanup: @@ -1586,19 +1604,67 @@ err_with_lex_cleanup: thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; thd->reset_db(save_db.str, save_db.length); - DBUG_RETURN(1); + /* Fall trough to error */ } + } +error: + if (!thd->is_error()) + { /* We don't care about this error message much because .TRG files will be merged into .FRM anyway. */ my_error(ER_WRONG_OBJECT, MYF(0), table_name, TRG_EXT + 1, "TRIGGER"); - DBUG_RETURN(1); + } + DBUG_RETURN(1); +} + + +/** + Add trigger in the correct position according to ordering clause + Also update action order + + If anchor_trigger doesn't exist, add it last. +*/ + +void Table_triggers_list::add_trigger(trg_event_type event, + trg_action_time_type action_time, + trigger_order_type ordering_clause, + LEX_STRING *anchor_trigger_name, + Trigger *trigger) +{ + Trigger **parent= &triggers[event][action_time]; + uint position= 0; + + for ( ; *parent ; parent= &(*parent)->next, position++) + { + if (ordering_clause != TRG_ORDER_NONE && + !my_strcasecmp(table_alias_charset, anchor_trigger_name->str, + (*parent)->name.str)) + { + if (ordering_clause == TRG_ORDER_FOLLOWS) + { + parent= &(*parent)->next; // Add after this one + position++; + } + break; + } } - DBUG_RETURN(1); + /* Add trigger where parent points to */ + trigger->next= *parent; + *parent= trigger; + + /* Update action_orders and position */ + trigger->event= event; + trigger->action_time= action_time; + trigger->action_order= ++position; + while ((trigger= trigger->next)) + trigger->action_order= ++position; + + count++; } @@ -1606,11 +1672,7 @@ err_with_lex_cleanup: Obtains and returns trigger metadata. @param thd current thread context - @param event trigger event type - @param time_type trigger action time - @param trigger_name returns name of trigger @param trigger_stmt returns statement of trigger - @param sql_mode returns sql_mode of trigger @param definer returns definer/creator of trigger. The caller is responsible to allocate enough space for storing definer information. @@ -1621,106 +1683,34 @@ err_with_lex_cleanup: True error */ -bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event, - trg_action_time_type time_type, - LEX_STRING *trigger_name, - LEX_STRING *trigger_stmt, - ulong *sql_mode, - LEX_STRING *definer, - LEX_STRING *client_cs_name, - LEX_STRING *connection_cl_name, - LEX_STRING *db_cl_name) +void Trigger::get_trigger_info(LEX_STRING *trigger_stmt, + LEX_STRING *trigger_body, LEX_STRING *definer) { - sp_head *body; DBUG_ENTER("get_trigger_info"); - if ((body= bodies[event][time_type])) + + *trigger_stmt= definition; + if (!body) { - Stored_program_creation_ctx *creation_ctx= - bodies[event][time_type]->get_creation_ctx(); - - *trigger_name= body->m_name; - *trigger_stmt= body->m_body_utf8; - *sql_mode= body->m_sql_mode; - - if (body->m_chistics->suid == SP_IS_NOT_SUID) - { - definer->str[0]= 0; - definer->length= 0; - } - else - { - definer->length= strxmov(definer->str, body->m_definer_user.str, "@", - body->m_definer_host.str, NullS) - definer->str; - } - - lex_string_set(client_cs_name, - creation_ctx->get_client_cs()->csname); - - lex_string_set(connection_cl_name, - creation_ctx->get_connection_cl()->name); - - lex_string_set(db_cl_name, - creation_ctx->get_db_cl()->name); - - DBUG_RETURN(0); + /* Parse error */ + *trigger_body= definition; + *definer= empty_lex_str; + DBUG_VOID_RETURN; } - DBUG_RETURN(1); + *trigger_body= body->m_body_utf8; + + if (body->m_chistics->suid == SP_IS_NOT_SUID) + { + *definer= empty_lex_str; + } + else + { + definer->length= strxmov(definer->str, body->m_definer_user.str, "@", + body->m_definer_host.str, NullS) - definer->str; + } + DBUG_VOID_RETURN; } -void Table_triggers_list::get_trigger_info(THD *thd, - int trigger_idx, - LEX_STRING *trigger_name, - ulonglong *sql_mode, - LEX_STRING *sql_original_stmt, - LEX_STRING *client_cs_name, - LEX_STRING *connection_cl_name, - LEX_STRING *db_cl_name) -{ - List_iterator_fast it_trigger_name(names_list); - List_iterator_fast it_sql_mode(definition_modes_list); - List_iterator_fast it_sql_orig_stmt(definitions_list); - List_iterator_fast it_client_cs_name(client_cs_names); - List_iterator_fast it_connection_cl_name(connection_cl_names); - List_iterator_fast it_db_cl_name(db_cl_names); - - for (int i = 0; i < trigger_idx; ++i) - { - it_trigger_name.next_fast(); - it_sql_mode.next_fast(); - it_sql_orig_stmt.next_fast(); - - it_client_cs_name.next_fast(); - it_connection_cl_name.next_fast(); - it_db_cl_name.next_fast(); - } - - *trigger_name= *(it_trigger_name++); - *sql_mode= *(it_sql_mode++); - *sql_original_stmt= *(it_sql_orig_stmt++); - - *client_cs_name= *(it_client_cs_name++); - *connection_cl_name= *(it_connection_cl_name++); - *db_cl_name= *(it_db_cl_name++); -} - - -int Table_triggers_list::find_trigger_by_name(const LEX_STRING *trg_name) -{ - List_iterator_fast it(names_list); - - for (int i = 0; ; ++i) - { - LEX_STRING *cur_name= it++; - - if (!cur_name) - return -1; - - if (strcmp(cur_name->str, trg_name->str) == 0) - return i; - } -} - /** Find trigger's table from trigger identifier and add it to the statement table list. @@ -1811,38 +1801,37 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name) } if (table.triggers) { - LEX_STRING *trigger; - List_iterator_fast it_name(table.triggers->names_list); - - while ((trigger= it_name++)) + for (uint i= 0; i < (uint)TRG_EVENT_MAX; i++) { - /* - Trigger, which body we failed to parse during call - Table_triggers_list::check_n_load(), might be missing name. - Such triggers have zero-length name and are skipped here. - */ - if (trigger->length == 0) - continue; - if (rm_trigname_file(path, db, trigger->str)) + for (uint j= 0; j < (uint)TRG_ACTION_MAX; j++) { - /* - Instead of immediately bailing out with error if we were unable - to remove .TRN file we will try to drop other files. - */ - result= 1; - continue; + Trigger *trigger; + for (trigger= table.triggers->get_trigger(i,j) ; + trigger ; + trigger= trigger->next) + { + /* + Trigger, which body we failed to parse during call + Table_triggers_list::check_n_load(), might be missing name. + Such triggers have zero-length name and are skipped here. + */ + if (trigger->name.length && + rm_trigname_file(path, db, trigger->name.str)) + { + /* + Instead of immediately bailing out with error if we were unable + to remove .TRN file we will try to drop other files. + */ + result= 1; + } + } } } - if (rm_trigger_file(path, db, name)) - { result= 1; - goto end; - } + delete table.triggers; } end: - if (table.triggers) - delete table.triggers; free_root(&table.mem_root, MYF(0)); DBUG_RETURN(result); } @@ -1864,6 +1853,16 @@ end: TRUE Failure */ +struct change_table_name_param +{ + THD *thd; + const char *old_db_name; + const char *new_db_name; + LEX_STRING *new_table_name; + Trigger *stopper; +}; + + bool Table_triggers_list::change_table_name_in_triggers(THD *thd, const char *old_db_name, @@ -1871,57 +1870,23 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd, LEX_STRING *old_table_name, LEX_STRING *new_table_name) { - char path_buff[FN_REFLEN]; - LEX_STRING *def, *on_table_name, new_def; + struct change_table_name_param param; ulonglong save_sql_mode= thd->variables.sql_mode; - List_iterator_fast it_def(definitions_list); - List_iterator_fast it_on_table_name(on_table_names_list); - List_iterator_fast it_mode(definition_modes_list); - size_t on_q_table_name_len, before_on_len; - String buff; + char path_buff[FN_REFLEN]; - DBUG_ASSERT(definitions_list.elements == on_table_names_list.elements && - definitions_list.elements == definition_modes_list.elements); + param.thd= thd; + param.new_table_name= new_table_name; - while ((def= it_def++)) - { - on_table_name= it_on_table_name++; - thd->variables.sql_mode= (ulong) *(it_mode++); - - /* Construct CREATE TRIGGER statement with new table name. */ - buff.length(0); - - /* WARNING: 'on_table_name' is supposed to point inside 'def' */ - DBUG_ASSERT(on_table_name->str > def->str); - DBUG_ASSERT(on_table_name->str < (def->str + def->length)); - before_on_len= on_table_name->str - def->str; - - buff.append(def->str, before_on_len); - buff.append(STRING_WITH_LEN("ON ")); - append_identifier(thd, &buff, new_table_name->str, new_table_name->length); - buff.append(STRING_WITH_LEN(" ")); - on_q_table_name_len= buff.length() - before_on_len; - buff.append(on_table_name->str + on_table_name->length, - def->length - (before_on_len + on_table_name->length)); - /* - It is OK to allocate some memory on table's MEM_ROOT since this - table instance will be thrown out at the end of rename anyway. - */ - new_def.str= (char*) memdup_root(&trigger_table->mem_root, buff.ptr(), - buff.length()); - new_def.length= buff.length(); - on_table_name->str= new_def.str + before_on_len; - on_table_name->length= on_q_table_name_len; - *def= new_def; - } + for_all_triggers(&Trigger::change_table_name, ¶m); thd->variables.sql_mode= save_sql_mode; if (thd->is_fatal_error) return TRUE; /* OOM */ - if (save_trigger_file(this, new_db_name, new_table_name->str)) + if (save_trigger_file(thd, new_db_name, new_table_name->str)) return TRUE; + if (rm_trigger_file(path_buff, old_db_name, old_table_name->str)) { (void) rm_trigger_file(path_buff, new_db_name, new_table_name->str); @@ -1931,6 +1896,47 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd, } +bool Trigger::change_table_name(void* param_arg) +{ + change_table_name_param *param= (change_table_name_param*) param_arg; + THD *thd= param->thd; + LEX_STRING *new_table_name= param->new_table_name; + + LEX_STRING *def= &definition, new_def; + size_t on_q_table_name_len, before_on_len; + String buff; + + thd->variables.sql_mode= sql_mode; + + /* Construct CREATE TRIGGER statement with new table name. */ + buff.length(0); + + /* WARNING: 'on_table_name' is supposed to point inside 'def' */ + DBUG_ASSERT(on_table_name.str > def->str); + DBUG_ASSERT(on_table_name.str < (def->str + def->length)); + before_on_len= on_table_name.str - def->str; + + buff.append(def->str, before_on_len); + buff.append(STRING_WITH_LEN("ON ")); + append_identifier(thd, &buff, new_table_name->str, new_table_name->length); + buff.append(STRING_WITH_LEN(" ")); + on_q_table_name_len= buff.length() - before_on_len; + buff.append(on_table_name.str + on_table_name.length, + def->length - (before_on_len + on_table_name.length)); + /* + It is OK to allocate some memory on table's MEM_ROOT since this + table instance will be thrown out at the end of rename anyway. + */ + new_def.str= (char*) memdup_root(&base->trigger_table->mem_root, buff.ptr(), + buff.length()); + new_def.length= buff.length(); + on_table_name.str= new_def.str + before_on_len; + on_table_name.length= on_q_table_name_len; + definition= new_def; + return 0; +} + + /** Iterate though Table_triggers_list::names_list list and update .TRN files after renaming triggers' subject table. @@ -1948,42 +1954,56 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd, for which update failed. */ -LEX_STRING* +Trigger * Table_triggers_list::change_table_name_in_trignames(const char *old_db_name, const char *new_db_name, LEX_STRING *new_table_name, - LEX_STRING *stopper) + Trigger *trigger) { + struct change_table_name_param param; + param.old_db_name= old_db_name; + param.new_db_name= new_db_name; + param.new_table_name= new_table_name; + param.stopper= trigger; + + return for_all_triggers(&Trigger::change_on_table_name, ¶m); +} + + +bool Trigger::change_on_table_name(void* param_arg) +{ + change_table_name_param *param= (change_table_name_param*) param_arg; + char trigname_buff[FN_REFLEN]; struct st_trigname trigname; LEX_STRING trigname_file; - LEX_STRING *trigger; - List_iterator_fast it_name(names_list); - while ((trigger= it_name++) != stopper) + if (param->stopper == this) + return 0; // Stop processing + + trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, + param->new_db_name, name.str, + TRN_EXT, 0); + trigname_file.str= trigname_buff; + + trigname.trigger_table= *param->new_table_name; + + if (base->create_lists_needed_for_files(current_thd->mem_root)) + return true; + + if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type, + (uchar*)&trigname, trigname_file_parameters)) + return this; + + /* Remove stale .TRN file in case of database upgrade */ + if (param->old_db_name) { - trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, - new_db_name, trigger->str, - TRN_EXT, 0); - trigname_file.str= trigname_buff; - - trigname.trigger_table= *new_table_name; - - if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type, - (uchar*)&trigname, trigname_file_parameters)) - return trigger; - - /* Remove stale .TRN file in case of database upgrade */ - if (old_db_name) + if (rm_trigname_file(trigname_buff, param->old_db_name, name.str)) { - if (rm_trigname_file(trigname_buff, old_db_name, trigger->str)) - { - (void) rm_trigname_file(trigname_buff, new_db_name, trigger->str); - return trigger; - } + (void) rm_trigname_file(trigname_buff, param->new_db_name, name.str); + return 1; } } - return 0; } @@ -2017,8 +2037,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, { TABLE table; bool result= 0; - bool upgrading50to51= FALSE; - LEX_STRING *err_trigname; + bool upgrading50to51= FALSE; + Trigger *err_trigger; DBUG_ENTER("change_table_name"); bzero(&table, sizeof(table)); @@ -2053,7 +2073,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, moving table with them between two schemas raises too many questions. (E.g. what should happen if in new schema we already have trigger with same name ?). - + In case of "ALTER DATABASE `#mysql50#db1` UPGRADE DATA DIRECTORY NAME" we will be given table name with "#mysql50#" prefix To remove this prefix we use check_n_cut_mysql50_prefix(). @@ -2061,7 +2081,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, if (my_strcasecmp(table_alias_charset, db, new_db)) { char dbname[SAFE_NAME_LEN + 1]; - if (check_n_cut_mysql50_prefix(db, dbname, sizeof(dbname)) && + if (check_n_cut_mysql50_prefix(db, dbname, sizeof(dbname)) && !my_strcasecmp(table_alias_charset, dbname, new_db)) { upgrading50to51= TRUE; @@ -2080,8 +2100,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, result= 1; goto end; } - if ((err_trigname= table.triggers->change_table_name_in_trignames( - upgrading50to51 ? db : NULL, + if ((err_trigger= table.triggers-> + change_table_name_in_trignames( upgrading50to51 ? db : NULL, new_db, &new_table_name, 0))) { /* @@ -2092,7 +2112,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, */ (void) table.triggers->change_table_name_in_trignames( upgrading50to51 ? new_db : NULL, db, - &old_table_name, err_trigname); + &old_table_name, err_trigger); (void) table.triggers->change_table_name_in_triggers( thd, db, new_db, &new_table_name, &old_table_name); @@ -2100,7 +2120,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, goto end; } } - + end: delete table.triggers; free_root(&table.mem_root, MYF(0)); @@ -2131,17 +2151,15 @@ bool Table_triggers_list::process_triggers(THD *thd, { bool err_status; Sub_statement_state statement_state; - sp_head *sp_trigger= bodies[event][time_type]; + Trigger *trigger; SELECT_LEX *save_current_select; if (check_for_broken_triggers()) - return true; + return TRUE; - if (sp_trigger == NULL) + if (!(trigger= get_trigger(event, time_type))) return FALSE; - status_var_increment(thd->status_var.executed_triggers); - if (old_row_is_record1) { old_field= record1_field; @@ -2168,12 +2186,16 @@ bool Table_triggers_list::process_triggers(THD *thd, in case of failure during trigger execution. */ save_current_select= thd->lex->current_select; - thd->lex->current_select= NULL; - err_status= - sp_trigger->execute_trigger(thd, - &trigger_table->s->db, - &trigger_table->s->table_name, - &subject_table_grants[event][time_type]); + + do { + thd->lex->current_select= NULL; + err_status= + trigger->body->execute_trigger(thd, + &trigger_table->s->db, + &trigger_table->s->table_name, + &trigger->subject_table_grants); + status_var_increment(thd->status_var.executed_triggers); + } while (!err_status && (trigger= trigger->next)); thd->lex->current_select= save_current_select; thd->restore_sub_statement_state(&statement_state); @@ -2211,11 +2233,15 @@ add_tables_and_routines_for_triggers(THD *thd, { for (int j= 0; j < (int)TRG_ACTION_MAX; j++) { - /* We can have only one trigger per action type currently */ - sp_head *trigger= table_list->table->triggers->bodies[i][j]; + Trigger *triggers= table_list->table->triggers->get_trigger(i,j); - if (trigger) + for ( ; triggers ; triggers= triggers->next) { + sp_head *trigger= triggers->body; + + if (!triggers->body) // Parse error + continue; + MDL_key key(MDL_key::TRIGGER, trigger->m_db.str, trigger->m_name.str); if (sp_add_used_routine(prelocking_ctx, thd->stmt_arena, @@ -2245,13 +2271,11 @@ add_tables_and_routines_for_triggers(THD *thd, @param action_time Type of trigger action time we are going to inspect */ -bool Table_triggers_list::is_fields_updated_in_trigger(MY_BITMAP *used_fields, - trg_event_type event_type, - trg_action_time_type action_time) +bool Trigger::is_fields_updated_in_trigger(MY_BITMAP *used_fields) { Item_trigger_field *trg_field; - sp_head *sp= bodies[event_type][action_time]; - DBUG_ASSERT(used_fields->n_bits == trigger_table->s->fields); + sp_head *sp= body; + DBUG_ASSERT(used_fields->n_bits == base->trigger_table->s->fields); for (trg_field= sp->m_trg_table_fields.first; trg_field; trg_field= trg_field->next_trg_field) @@ -2288,15 +2312,21 @@ void Table_triggers_list::mark_fields_used(trg_event_type event) for (action_time= 0; action_time < (int)TRG_ACTION_MAX; action_time++) { - for (trg_field= trigger_fields[event][action_time]; trg_field; - trg_field= trg_field->next_trg_field) + for (Trigger *trigger= get_trigger(event,action_time); + trigger ; + trigger= trigger->next) { - /* We cannot mark fields which does not present in table. */ - if (trg_field->field_idx != (uint)-1) + for (trg_field= trigger->trigger_fields; + trg_field; + trg_field= trg_field->next_trg_field) { - bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); - if (trg_field->get_settable_routine_parameter()) - bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); + /* We cannot mark fields which does not present in table. */ + if (trg_field->field_idx != (uint)-1) + { + bitmap_set_bit(trigger_table->read_set, trg_field->field_idx); + if (trg_field->get_settable_routine_parameter()) + bitmap_set_bit(trigger_table->write_set, trg_field->field_idx); + } } } } diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index fa858a0582b..f1161cdd967 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -51,22 +51,92 @@ enum trg_action_time_type TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; +enum trigger_order_type +{ + TRG_ORDER_NONE= 0, + TRG_ORDER_FOLLOWS= 1, + TRG_ORDER_PRECEDES= 2 +}; + + +struct st_trg_execution_order +{ + /** + FOLLOWS or PRECEDES as specified in the CREATE TRIGGER statement. + */ + enum trigger_order_type ordering_clause; + + /** + Trigger name referenced in the FOLLOWS/PRECEDES clause of the + CREATE TRIGGER statement. + */ + LEX_STRING anchor_trigger_name; +}; + + +class Table_triggers_list; /** - This class holds all information about triggers of table. - - TODO: Will it be merged into TABLE in the future ? + The trigger object */ -class Table_triggers_list: public Sql_alloc +class Trigger :public Sql_alloc { - /** Triggers as SPs grouped by event, action_time */ - sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX]; +public: + Trigger(Table_triggers_list *base_arg, sp_head *code): + base(base_arg), body(code), next(0), trigger_fields(0), action_order(0) + { + bzero((char *)&subject_table_grants, sizeof(subject_table_grants)); + } + ~Trigger(); + Table_triggers_list *base; + sp_head *body; + Trigger *next; /* Next trigger of same type */ + /** Heads of the lists linking items for all fields used in triggers grouped by event and action_time. */ - Item_trigger_field *trigger_fields[TRG_EVENT_MAX][TRG_ACTION_MAX]; + Item_trigger_field *trigger_fields; + LEX_STRING name; + LEX_STRING on_table_name; /* Raw table name */ + LEX_STRING definition; + LEX_STRING definer; + + /* Character sets used */ + LEX_STRING client_cs_name; + LEX_STRING connection_cl_name; + LEX_STRING db_cl_name; + + GRANT_INFO subject_table_grants; + ulonglong sql_mode; + /* Store create time. Can't be mysql_time_t as this holds also sub seconds */ + ulonglong create_time; + trg_event_type event; + trg_action_time_type action_time; + uint action_order; + + bool is_fields_updated_in_trigger(MY_BITMAP *used_fields); + void get_trigger_info(LEX_STRING *stmt, LEX_STRING *body, + LEX_STRING *definer); + /* Functions executed over each active trigger */ + bool change_on_table_name(void* param_arg); + bool change_table_name(void* param_arg); + bool add_to_file_list(void* param_arg); +}; + +typedef bool (Trigger::*Triggers_processor)(void *arg); + +/** + This class holds all information about triggers of table. +*/ + +class Table_triggers_list: public Sql_alloc +{ + friend class Trigger; + + /* Points to first trigger for a certain type */ + Trigger *triggers[TRG_EVENT_MAX][TRG_ACTION_MAX]; /** Copy of TABLE::Field array which all fields made nullable (using extra_null_bitmap, if needed). Used for NEW values in @@ -90,22 +160,6 @@ class Table_triggers_list: public Sql_alloc /* TABLE instance for which this triggers list object was created */ TABLE *trigger_table; - /** - Names of triggers. - Should correspond to order of triggers on definitions_list, - used in CREATE/DROP TRIGGER for looking up trigger by name. - */ - List names_list; - /** - List of "ON table_name" parts in trigger definitions, used for - updating trigger definitions during RENAME TABLE. - */ - List on_table_names_list; - - /** - Grant information for each trigger (pair: subject table, trigger definer). - */ - GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX]; /** This flag indicates that one of the triggers was not parsed successfully, @@ -127,6 +181,7 @@ class Table_triggers_list: public Sql_alloc the trigger file. */ char m_parse_error_message[MYSQL_ERRMSG_SIZE]; + uint count; /* Number of triggers */ public: /** @@ -138,6 +193,8 @@ public: List of sql modes for triggers */ List definition_modes_list; + /** Create times for triggers */ + List create_times; List definers_list; @@ -152,11 +209,9 @@ public: Table_triggers_list(TABLE *table_arg) :record0_field(0), extra_null_bitmap(0), record1_field(0), trigger_table(table_arg), - m_has_unparseable_trigger(false) + m_has_unparseable_trigger(false), count(0) { - bzero((char *)bodies, sizeof(bodies)); - bzero((char *)trigger_fields, sizeof(trigger_fields)); - bzero((char *)&subject_table_grants, sizeof(subject_table_grants)); + bzero((char *) triggers, sizeof(triggers)); } ~Table_triggers_list(); @@ -165,26 +220,9 @@ public: bool process_triggers(THD *thd, trg_event_type event, trg_action_time_type time_type, bool old_row_is_record1); - - bool get_trigger_info(THD *thd, trg_event_type event, - trg_action_time_type time_type, - LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, - ulong *sql_mode, - LEX_STRING *definer, - LEX_STRING *client_cs_name, - LEX_STRING *connection_cl_name, - LEX_STRING *db_cl_name); - - void get_trigger_info(THD *thd, - int trigger_idx, - LEX_STRING *trigger_name, - ulonglong *sql_mode, - LEX_STRING *sql_original_stmt, - LEX_STRING *client_cs_name, - LEX_STRING *connection_cl_name, - LEX_STRING *db_cl_name); - - int find_trigger_by_name(const LEX_STRING *trigger_name); + void empty_lists(); + bool create_lists_needed_for_files(MEM_ROOT *root); + bool save_trigger_file(THD *thd, const char *db, const char *table_name); static bool check_n_load(THD *thd, const char *db, const char *table_name, TABLE *table, bool names_only); @@ -194,15 +232,32 @@ public: const char *old_table, const char *new_db, const char *new_table); + void add_trigger(trg_event_type event_type, + trg_action_time_type action_time, + trigger_order_type ordering_clause, + LEX_STRING *anchor_trigger_name, + Trigger *trigger); + Trigger *get_trigger(trg_event_type event_type, + trg_action_time_type action_time) + { + return triggers[event_type][action_time]; + } + /* Simpler version of the above, to avoid casts in the code */ + Trigger *get_trigger(uint event_type, uint action_time) + { + return get_trigger((trg_event_type) event_type, + (trg_action_time_type) action_time); + } + bool has_triggers(trg_event_type event_type, trg_action_time_type action_time) { - return (bodies[event_type][action_time] != NULL); + return get_trigger(event_type,action_time) != 0; } bool has_delete_triggers() { - return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] || - bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]); + return (has_triggers(TRG_EVENT_DELETE,TRG_ACTION_BEFORE) || + has_triggers(TRG_EVENT_DELETE,TRG_ACTION_AFTER)); } void mark_fields_used(trg_event_type event); @@ -215,10 +270,6 @@ public: Query_tables_list *prelocking_ctx, TABLE_LIST *table_list); - bool is_fields_updated_in_trigger(MY_BITMAP *used_fields, - trg_event_type event_type, - trg_action_time_type action_time); - Field **nullable_fields() { return record0_field; } void reset_extra_null_bitmap() { @@ -227,12 +278,16 @@ public: bzero(extra_null_bitmap, null_bytes); } + Trigger *find_trigger(const LEX_STRING *name, bool remove_from_list); + + Trigger* for_all_triggers(Triggers_processor func, void *arg); + private: bool prepare_record_accessors(TABLE *table); - LEX_STRING* change_table_name_in_trignames(const char *old_db_name, - const char *new_db_name, - LEX_STRING *new_table_name, - LEX_STRING *stopper); + Trigger *change_table_name_in_trignames(const char *old_db_name, + const char *new_db_name, + LEX_STRING *new_table_name, + Trigger *trigger); bool change_table_name_in_triggers(THD *thd, const char *old_db_name, const char *new_db_name, @@ -257,9 +312,6 @@ inline Field **TABLE::field_to_fill() } -extern const LEX_STRING trg_action_time_type_names[]; -extern const LEX_STRING trg_event_type_names[]; - bool add_table_for_trigger(THD *thd, const sp_name *trg_name, bool continue_if_not_exist, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1865f2e6321..4a88c1f2ddf 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -995,6 +995,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, const char *txt, class Window_frame *window_frame; class Window_frame_bound *window_frame_bound; udf_func *udf; + st_trg_execution_order trg_execution_order; /* enums */ enum Condition_information_item::Name cond_info_item_name; @@ -1022,6 +1023,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, const char *txt, enum Window_frame_bound::Bound_precedence_type bound_precedence_type; enum Window_frame::Frame_units frame_units; enum Window_frame::Frame_exclusion frame_exclusion; + enum trigger_order_type trigger_action_order_type; DDL_options_st object_ddl_options; } @@ -1251,6 +1253,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FLOAT_NUM %token FLOAT_SYM /* SQL-2003-R */ %token FLUSH_SYM +%token FOLLOWS_SYM /* MYSQL trigger*/ %token FOLLOWING_SYM %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ @@ -1476,6 +1479,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token POLYGON %token PORT_SYM %token POSITION_SYM /* SQL-2003-N */ +%token PRECEDES_SYM /* MYSQL */ %token PRECEDING_SYM %token PRECISION /* SQL-2003-R */ %token PREPARE_SYM /* SQL-2003-R */ @@ -2030,6 +2034,9 @@ END_OF_INPUT %type signal_stmt resignal_stmt %type signal_condition_information_item_name +%type trigger_follows_precedes_clause; +%type trigger_action_order; + %type which_area; %type diagnostics_information; %type statement_information_item; @@ -14537,6 +14544,7 @@ keyword: | EXAMINED_SYM {} | EXECUTE_SYM {} | FLUSH_SYM {} + | FOLLOWS_SYM {} | FORMAT_SYM {} | GET_SYM {} | HANDLER_SYM {} @@ -14551,6 +14559,7 @@ keyword: | OWNER_SYM {} | PARSER_SYM {} | PORT_SYM {} + | PRECEDES_SYM {} | PREPARE_SYM {} | REMOVE_SYM {} | REPAIR {} @@ -16508,10 +16517,12 @@ view_select: { LEX *lex= Lex; uint len= YYLIP->get_cpp_ptr() - lex->create_view_select.str; + uint not_used; void *create_view_select= thd->memdup(lex->create_view_select.str, len); lex->create_view_select.length= len; lex->create_view_select.str= (char *) create_view_select; - trim_whitespace(thd->charset(), &lex->create_view_select); + trim_whitespace(thd->charset(), &lex->create_view_select, + ¬_used); lex->parsing_options.allows_variable= TRUE; lex->current_select->set_with_clause($2); } @@ -16545,6 +16556,28 @@ view_check_option: **************************************************************************/ +trigger_action_order: + FOLLOWS_SYM + { $$= TRG_ORDER_FOLLOWS; } + | PRECEDES_SYM + { $$= TRG_ORDER_PRECEDES; } + ; + +trigger_follows_precedes_clause: + /* empty */ + { + $$.ordering_clause= TRG_ORDER_NONE; + $$.anchor_trigger_name.str= NULL; + $$.anchor_trigger_name.length= 0; + } + | + trigger_action_order ident_or_text + { + $$.ordering_clause= $1; + $$.anchor_trigger_name= $2; + } + ; + trigger_tail: TRIGGER_SYM remember_name @@ -16569,7 +16602,11 @@ trigger_tail: } EACH_SYM ROW_SYM - { /* $17 */ + { + Lex->trg_chistics.ordering_clause_begin= YYLIP->get_cpp_ptr(); + } + trigger_follows_precedes_clause /* $18 */ + { /* $19 */ LEX *lex= thd->lex; Lex_input_stream *lip= YYLIP; @@ -16580,14 +16617,16 @@ trigger_tail: lex->ident.str= $9; lex->ident.length= $13 - $9; lex->spname= $5; + (*static_cast(&lex->trg_chistics))= ($18); + lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr(); if (!make_sp_head(thd, $5, TYPE_ENUM_TRIGGER)) MYSQL_YYABORT; - lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); + lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); } - sp_proc_stmt /* $18 */ - { /* $19 */ + sp_proc_stmt /* $20 */ + { /* $21 */ LEX *lex= Lex; sp_head *sp= lex->sphead; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5cc81585ed5..7f4d988b072 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3088,7 +3088,8 @@ static const char *sql_mode_names[]= "PAD_CHAR_TO_FULL_LENGTH", 0 }; -export bool sql_mode_string_representation(THD *thd, ulonglong sql_mode, + +export bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode, LEX_STRING *ls) { set_to_string(thd, ls, sql_mode, sql_mode_names); diff --git a/sql/table.cc b/sql/table.cc index 9a9dee6e0ca..8d0a40858da 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -23,7 +23,6 @@ #include "key.h" // find_ref_key #include "sql_table.h" // build_table_filename, // primary_key_name -#include "sql_trigger.h" #include "sql_parse.h" // free_items #include "strfunc.h" // unhex_type2 #include "sql_partition.h" // mysql_unpack_partition, @@ -31,6 +30,7 @@ #include "sql_acl.h" // *_ACL, acl_getroot_no_password #include "sql_base.h" #include "create_options.h" +#include "sql_trigger.h" #include #include "my_md5.h" #include "my_bit.h" diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a8253ddf3ad..d18ee0efff2 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2570,10 +2570,11 @@ static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) append_definer(thd, &stmt_query, &definer_user, &definer_host); LEX_STRING stmt_definition; + uint not_used; stmt_definition.str= (char*) thd->lex->stmt_definition_begin; stmt_definition.length= thd->lex->stmt_definition_end - thd->lex->stmt_definition_begin; - trim_whitespace(thd->charset(), & stmt_definition); + trim_whitespace(thd->charset(), &stmt_definition, ¬_used); stmt_query.append(stmt_definition.str, stmt_definition.length);