summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2015-03-04 09:52:01 +0400
committerAlexander Barkov <bar@mariadb.org>2015-03-04 09:52:01 +0400
commit87b0cc99123e5d6923c77ac3e08c4e9ed0d4d769 (patch)
tree1dfc0f010060d53a1db9547e4464b662faf112d2
parenta7ed8523e35ff2e82701cd1f483c8f665f322f3b (diff)
downloadmariadb-git-87b0cc99123e5d6923c77ac3e08c4e9ed0d4d769.tar.gz
MDEV-7286 TRIGGER: CREATE OR REPLACE, CREATE IF NOT EXISTS
Based on the patch by Sriram Patil, made under terms of GSoC 2014.
-rw-r--r--mysql-test/r/create.result5
-rw-r--r--mysql-test/r/create_drop_binlog.result37
-rw-r--r--mysql-test/r/create_drop_trigger.result37
-rw-r--r--mysql-test/r/create_or_replace.result2
-rw-r--r--mysql-test/r/trigger.result2
-rw-r--r--mysql-test/suite/rpl/r/rpl_create_drop_trigger.result48
-rw-r--r--mysql-test/suite/rpl/t/rpl_create_drop_trigger.test48
-rw-r--r--mysql-test/t/create.test8
-rw-r--r--mysql-test/t/create_drop_binlog.test16
-rw-r--r--mysql-test/t/create_drop_trigger.test31
-rw-r--r--mysql-test/t/create_or_replace.test2
-rw-r--r--mysql-test/t/trigger.test4
-rw-r--r--sql/sql_trigger.cc164
-rw-r--r--sql/sql_yacc.yy45
14 files changed, 356 insertions, 93 deletions
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index ec70dba674f..e90dba00206 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -2120,6 +2120,11 @@ CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
UPDATE A SET `pk`=1 WHERE `pk`=0 ;
END ;|
+ERROR HY000: Trigger already exists
+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_binlog.result b/mysql-test/r/create_drop_binlog.result
index bfe99789b9f..f7aaedf9118 100644
--- a/mysql-test/r/create_drop_binlog.result
+++ b/mysql-test/r/create_drop_binlog.result
@@ -267,3 +267,40 @@ Log_name Pos Event_type Server_id End_log_pos Info
# # Gtid 1 # GTID #-#-#
# # Query 1 # use `test`; DROP EVENT IF EXISTS ev1
RESET MASTER;
+CREATE TABLE t1 (a INT);
+CREATE OR REPLACE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=10;
+CREATE OR REPLACE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=11;
+DROP TRIGGER tr1;
+CREATE TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=20;
+CREATE TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=21;
+Warnings:
+Note 1359 Trigger already exists
+DROP TRIGGER IF EXISTS tr1;
+DROP TRIGGER IF EXISTS tr1;
+Warnings:
+Note 1360 Trigger does not exist
+DROP TABLE t1;
+SHOW BINLOG EVENTS;
+Log_name Pos Event_type Server_id End_log_pos Info
+# # Format_desc 1 # VER
+# # Gtid_list 1 # []
+# # Binlog_checkpoint 1 # master-bin.000001
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; CREATE TABLE t1 (a INT)
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=10
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=11
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; DROP TRIGGER tr1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=20
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=21
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; DROP TRIGGER IF EXISTS tr1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; DROP TRIGGER IF EXISTS tr1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # use `test`; DROP TABLE `t1` /* generated by server */
+RESET MASTER;
diff --git a/mysql-test/r/create_drop_trigger.result b/mysql-test/r/create_drop_trigger.result
new file mode 100644
index 00000000000..a215838b0fd
--- /dev/null
+++ b/mysql-test/r/create_drop_trigger.result
@@ -0,0 +1,37 @@
+CREATE DATABASE db1;
+USE db1;
+CREATE TABLE t1 (val INT);
+CREATE TRIGGER IF NOT EXISTS val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val;
+SET @sum=0;
+INSERT INTO t1 VALUES (10), (20), (30);
+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
+CREATE OR REPLACE TRIGGER IF NOT EXISTS val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 2 + NEW.val;
+ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT
+SET @sum = @sum + NEW.val
+CREATE OR REPLACE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 3 + NEW.val;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT
+SET @sum = @sum + 3 + NEW.val
+CREATE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 4 + NEW.val;
+ERROR HY000: Trigger already exists
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT
+SET @sum = @sum + 3 + NEW.val
+# Clearing up
+DROP TRIGGER IF EXISTS val_sum;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT
+DROP TRIGGER IF EXISTS val_sum;
+Warnings:
+Note 1360 Trigger does not exist
+DROP TABLE t1;
+DROP DATABASE db1;
diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result
index ff8170b7309..87c61360151 100644
--- a/mysql-test/r/create_or_replace.result
+++ b/mysql-test/r/create_or_replace.result
@@ -6,8 +6,6 @@ INSERT INTO t2 VALUES(1),(2),(3);
#
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int);
ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS
-create or replace trigger trg before insert on t1 for each row set @a:=1;
-ERROR HY000: Incorrect usage of OR REPLACE and TRIGGERS / SP / EVENT
create or replace table mysql.general_log (a int);
ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled
create or replace table mysql.slow_log (a int);
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 8bf31766031..e71090b8528 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1957,6 +1957,8 @@ drop table if exists t1;
create table t1 (i int, j int);
create trigger t1_bi before insert on t1 for each row begin end;
create trigger t1_bi before insert on t1 for each row begin end;
+ERROR HY000: Trigger already exists
+create trigger t1_bi2 before insert on t1 for each row begin end;
ERROR 42000: This version of MariaDB doesn't yet support 'multiple triggers with the same action time and event for one table'
drop trigger t1_bi;
drop trigger t1_bi;
diff --git a/mysql-test/suite/rpl/r/rpl_create_drop_trigger.result b/mysql-test/suite/rpl/r/rpl_create_drop_trigger.result
new file mode 100644
index 00000000000..8cb80613af8
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_create_drop_trigger.result
@@ -0,0 +1,48 @@
+include/master-slave.inc
+[connection master]
+# Part 1 - initial creation
+CREATE DATABASE db1;
+USE db1;
+CREATE TABLE t1 (val INT);
+CREATE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 1;
+SET @sum=0;
+INSERT INTO t1 VALUES (10), (20), (30);
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Master
+SET @sum = @sum + NEW.val + 1
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Slave
+SET @sum = @sum + NEW.val + 1
+# Part 2 - CREATE IF NOT EXISTS (on a existing trigger)
+CREATE TRIGGER IF NOT EXISTS val_sum AFTER INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 2;
+Warnings:
+Note 1359 Trigger already exists
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Master
+SET @sum = @sum + NEW.val + 1
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Slave
+SET @sum = @sum + NEW.val + 1
+# Part 3 - CREATE OR REPLACE (on a existing trigger)
+CREATE OR REPLACE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 3;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Master
+SET @sum = @sum + NEW.val + 3
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+ACTION_STATEMENT_Slave
+SET @sum = @sum + NEW.val + 3
+# Clearing up
+DROP TRIGGER val_sum;
+DROP TABLE t1;
+DROP TRIGGER IF EXISTS val_sum;
+Warnings:
+Note 1360 Trigger does not exist
+DROP TRIGGER random_trigger;
+ERROR HY000: Trigger does not exist
+DROP DATABASE db1;
+DROP TRIGGER IF EXISTS val_sum;
+ERROR 3D000: No database selected
+# Syncing slave with master
+DROP TRIGGER val_sum;
+ERROR HY000: Trigger does not exist
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test b/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test
new file mode 100644
index 00000000000..568d4e22aee
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_create_drop_trigger.test
@@ -0,0 +1,48 @@
+--source include/master-slave.inc
+
+--echo # Part 1 - initial creation
+connection master;
+CREATE DATABASE db1;
+USE db1;
+CREATE TABLE t1 (val INT);
+CREATE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 1;
+SET @sum=0;
+INSERT INTO t1 VALUES (10), (20), (30);
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+sync_slave_with_master;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+--echo # Part 2 - CREATE IF NOT EXISTS (on a existing trigger)
+connection master;
+CREATE TRIGGER IF NOT EXISTS val_sum AFTER INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 2;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+sync_slave_with_master;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+--echo # Part 3 - CREATE OR REPLACE (on a existing trigger)
+connection master;
+CREATE OR REPLACE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val + 3;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Master FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+sync_slave_with_master;
+SELECT ACTION_STATEMENT AS ACTION_STATEMENT_Slave FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+--echo # Clearing up
+connection master;
+DROP TRIGGER val_sum;
+DROP TABLE t1;
+DROP TRIGGER IF EXISTS val_sum;
+
+--error ER_TRG_DOES_NOT_EXIST
+DROP TRIGGER random_trigger;
+DROP DATABASE db1;
+
+--error ER_NO_DB_ERROR
+DROP TRIGGER IF EXISTS val_sum;
+
+--echo # Syncing slave with master
+sync_slave_with_master;
+
+--error ER_TRG_DOES_NOT_EXIST
+DROP TRIGGER val_sum;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 4d57a5a110a..30c93f58e2f 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -1622,12 +1622,18 @@ END ; |
INSERT INTO t1 (pk, int_key) SELECT `pk` , `int_key` FROM B ;
--delimiter |
---error ER_NOT_SUPPORTED_YET
+--error ER_TRG_ALREADY_EXISTS
CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW
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 ;
+END ;|
+
--delimiter ;
DROP TABLE t1;
diff --git a/mysql-test/t/create_drop_binlog.test b/mysql-test/t/create_drop_binlog.test
index b757a8bf994..2a0f183d5d8 100644
--- a/mysql-test/t/create_drop_binlog.test
+++ b/mysql-test/t/create_drop_binlog.test
@@ -127,6 +127,22 @@ CREATE OR REPLACE EVENT ev1 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE IF EXISTS t
SELECT EVENT_NAME, EVENT_DEFINITION FROM INFORMATION_SCHEMA.EVENTS;
DROP EVENT ev1;
DROP EVENT IF EXISTS ev1;
+
+--replace_column 1 # 2 # 5 #
+--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VER/
+SHOW BINLOG EVENTS;
+RESET MASTER;
+
+CREATE TABLE t1 (a INT);
+CREATE OR REPLACE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=10;
+CREATE OR REPLACE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=11;
+DROP TRIGGER tr1;
+CREATE TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=20;
+CREATE TRIGGER IF NOT EXISTS tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a=21;
+DROP TRIGGER IF EXISTS tr1;
+DROP TRIGGER IF EXISTS tr1;
+DROP TABLE t1;
+
--replace_column 1 # 2 # 5 #
--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VER/
SHOW BINLOG EVENTS;
diff --git a/mysql-test/t/create_drop_trigger.test b/mysql-test/t/create_drop_trigger.test
new file mode 100644
index 00000000000..a8afc8716d6
--- /dev/null
+++ b/mysql-test/t/create_drop_trigger.test
@@ -0,0 +1,31 @@
+CREATE DATABASE db1;
+USE db1;
+CREATE TABLE t1 (val INT);
+CREATE TRIGGER IF NOT EXISTS val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + NEW.val;
+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;
+
+--error ER_WRONG_USAGE
+CREATE OR REPLACE TRIGGER IF NOT EXISTS val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 2 + NEW.val;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+CREATE OR REPLACE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 3 + NEW.val;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+--error ER_TRG_ALREADY_EXISTS
+CREATE TRIGGER val_sum BEFORE INSERT ON t1 FOR EACH ROW SET @sum = @sum + 4 + NEW.val;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+
+--echo # Clearing up
+DROP TRIGGER IF EXISTS val_sum;
+SELECT ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_NAME='val_sum';
+DROP TRIGGER IF EXISTS val_sum;
+
+DROP TABLE t1;
+DROP DATABASE db1;
diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test
index 9e37950dbef..3e37910380c 100644
--- a/mysql-test/t/create_or_replace.test
+++ b/mysql-test/t/create_or_replace.test
@@ -21,8 +21,6 @@ INSERT INTO t2 VALUES(1),(2),(3);
--error ER_WRONG_USAGE
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int);
---error ER_WRONG_USAGE
-create or replace trigger trg before insert on t1 for each row set @a:=1;
# check that we don't try to create a log table in use
--error ER_BAD_LOG_STATEMENT
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 4a1a3a6167c..384dd6cdec5 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -2237,8 +2237,10 @@ drop table if exists t1;
create table t1 (i int, j int);
create trigger t1_bi before insert on t1 for each row begin end;
---error ER_NOT_SUPPORTED_YET
+--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;
--error ER_TRG_DOES_NOT_EXIST
drop trigger t1_bi;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 4b208134723..41e0ffe2df6 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -608,6 +608,63 @@ end:
DBUG_RETURN(result);
}
+/**
+ Build stmt_query to write it in the bin-log
+ and get the trigger definer.
+
+ @param thd current thread context (including trigger definition in
+ LEX)
+ @param tables table list containing one open table for which the
+ trigger is created.
+ @param[out] stmt_query after successful return, this string contains
+ well-formed statement for creation this trigger.
+
+ @param[out] trg_definer The triggger definer.
+ @param[out] trg_definer_holder Used as a buffer for definer.
+
+ @note
+ - Assumes that trigger name is fully qualified.
+ - NULL-string means the following LEX_STRING instance:
+ { str = 0; length = 0 }.
+ - In other words, definer_user and definer_host should contain
+ 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,
+ LEX_STRING *trg_definer,
+ char trg_definer_holder[])
+{
+ LEX *lex= thd->lex;
+
+ /*
+ Create a query with the full trigger definition.
+ The original query is not appropriate, as it can miss the DEFINER=XXX part.
+ */
+ stmt_query->append(STRING_WITH_LEN("CREATE "));
+
+ if (lex->create_info.or_replace())
+ stmt_query->append(STRING_WITH_LEN("OR REPLACE "));
+
+ if (lex->sphead->m_chistics->suid != SP_IS_NOT_SUID)
+ {
+ /* SUID trigger */
+ lex->definer->set_lex_string(trg_definer, trg_definer_holder);
+ append_definer(thd, stmt_query, &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);
+ stmt_query->append(stmt_definition.str, stmt_definition.length);
+}
+
/**
Create trigger for table.
@@ -640,8 +697,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
LEX_STRING file, trigname_file;
LEX_STRING *trg_def;
- LEX_STRING definer_user;
- LEX_STRING definer_host;
ulonglong *trg_sql_mode;
char trg_definer_holder[USER_HOST_BUFF_SIZE];
LEX_STRING *trg_definer;
@@ -650,6 +705,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
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];
if (check_for_broken_triggers())
return true;
@@ -659,20 +716,31 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
lex->spname->m_db.str))
{
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
- return 1;
+ return true;
}
- /* We don't allow creation of several triggers of the same type yet */
- if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time] != 0)
+ /*
+ 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 1;
+ return true;
}
if (sp_process_definer(thd))
- return 1;
+ return true;
/*
Let us check if all references to fields in old/new versions of row in
@@ -701,7 +769,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
if (!trg_field->fixed &&
trg_field->fix_fields(thd, (Item **)0))
- return 1;
+ return true;
}
/*
@@ -722,8 +790,29 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Use the filesystem to enforce trigger namespace constraints. */
if (!access(trigname_buff, F_OK))
{
- my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
- return 1;
+ 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;
+ }
+ else if (lex->create_info.if_not_exists())
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS),
+ trigname_buff);
+ LEX_STRING trg_definer_tmp;
+ build_trig_stmt_query(thd, tables, stmt_query,
+ &trg_definer_tmp, trg_definer_holder);
+ return false;
+ }
+ else
+ {
+ my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
+ return true;
+ }
}
trigname.trigger_table.str= tables->table_name;
@@ -731,7 +820,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
(uchar*)&trigname, trigname_file_parameters))
- return 1;
+ return true;
/*
Soon we will invalidate table object and thus Table_triggers_list object
@@ -764,29 +853,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
*trg_sql_mode= thd->variables.sql_mode;
- if (lex->sphead->m_chistics->suid != SP_IS_NOT_SUID)
- {
- /* SUID trigger. */
-
- definer_user= lex->definer->user;
- definer_host= lex->definer->host;
-
- lex->definer->set_lex_string(trg_definer, trg_definer_holder);
- }
- else
- {
- /* non-SUID trigger. */
-
- definer_user.str= 0;
- definer_user.length= 0;
-
- definer_host.str= 0;
- definer_host.length= 0;
-
- trg_definer->str= (char*) "";
- trg_definer->length= 0;
- }
-
/*
Fill character set information:
- client character set contains charset info only;
@@ -802,30 +868,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
lex_string_set(trg_db_cl_name,
get_default_db_collation(thd, tables->db)->name);
- /*
- Create well-formed trigger definition query. Original query is not
- appropriated, because definer-clause can be not truncated.
- */
-
- stmt_query->append(STRING_WITH_LEN("CREATE "));
-
- if (lex->sphead->m_chistics->suid != SP_IS_NOT_SUID)
- {
- /*
- Append definer-clause if the trigger is SUID (a usual trigger in
- new MySQL versions).
- */
-
- append_definer(thd, stmt_query, &definer_user, &definer_host);
- }
-
- 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);
-
- stmt_query->append(stmt_definition.str, stmt_definition.length);
+ build_trig_stmt_query(thd, tables, stmt_query,
+ trg_definer, trg_definer_holder);
trg_def->str= stmt_query->c_ptr_safe();
trg_def->length= stmt_query->length();
@@ -834,11 +878,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
(uchar*)this, triggers_file_parameters))
- return 0;
+ return false;
err_with_cleanup:
mysql_file_delete(key_file_trn, trigname_buff, MYF(MY_WME));
- return 1;
+ return true;
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f0b723b2d2a..ae6ba56c1e7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2560,20 +2560,6 @@ create:
Lex->create_view_suid= TRUE;
}
view_or_trigger_or_sp_or_event
- {
- // TODO: remove this when "MDEV-5359 CREATE OR REPLACE..." is done
- if ($1.or_replace() &&
- Lex->sql_command != SQLCOM_CREATE_EVENT &&
- Lex->sql_command != SQLCOM_CREATE_VIEW &&
- Lex->sql_command != SQLCOM_CREATE_FUNCTION &&
- Lex->sql_command != SQLCOM_CREATE_SPFUNCTION &&
- Lex->sql_command != SQLCOM_CREATE_PROCEDURE)
- {
- my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE",
- "TRIGGERS / SP / EVENT");
- MYSQL_YYABORT;
- }
- }
| create_or_replace USER opt_if_not_exists clear_privileges grant_list
{
if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3))
@@ -16159,23 +16145,28 @@ view_check_option:
trigger_tail:
TRIGGER_SYM
remember_name
+ opt_if_not_exists
+ {
+ if (Lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
+ }
sp_name
trg_action_time
trg_event
ON
- remember_name /* $7 */
- { /* $8 */
+ remember_name /* $9 */
+ { /* $10 */
Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start();
}
- table_ident /* $9 */
+ table_ident /* $11 */
FOR_SYM
- remember_name /* $11 */
- { /* $12 */
+ remember_name /* $13 */
+ { /* $14 */
Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start();
}
EACH_SYM
ROW_SYM
- { /* $15 */
+ { /* $17 */
LEX *lex= thd->lex;
Lex_input_stream *lip= YYLIP;
@@ -16186,17 +16177,17 @@ trigger_tail:
}
lex->stmt_definition_begin= $2;
- lex->ident.str= $7;
- lex->ident.length= $11 - $7;
- lex->spname= $3;
+ lex->ident.str= $9;
+ lex->ident.length= $13 - $9;
+ lex->spname= $5;
- if (!make_sp_head(thd, $3, TYPE_ENUM_TRIGGER))
+ if (!make_sp_head(thd, $5, TYPE_ENUM_TRIGGER))
MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
}
- sp_proc_stmt /* $16 */
- { /* $17 */
+ sp_proc_stmt /* $18 */
+ { /* $19 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -16212,7 +16203,7 @@ trigger_tail:
sp_proc_stmt alternatives are not saving/restoring LEX, so
lex->query_tables can be wiped out.
*/
- if (!lex->select_lex.add_table_to_list(thd, $9,
+ if (!lex->select_lex.add_table_to_list(thd, $11,
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
TL_READ_NO_INSERT,