Commit 87b0cc99 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-7286 TRIGGER: CREATE OR REPLACE, CREATE IF NOT EXISTS

Based on the patch by Sriram Patil, made under terms of GSoC 2014.
parent a7ed8523
...@@ -2120,6 +2120,11 @@ CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW ...@@ -2120,6 +2120,11 @@ CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW
BEGIN BEGIN
UPDATE A SET `pk`=1 WHERE `pk`=0 ; UPDATE A SET `pk`=1 WHERE `pk`=0 ;
END ;| 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' 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 t1;
DROP TABLE B; DROP TABLE B;
......
...@@ -267,3 +267,40 @@ Log_name Pos Event_type Server_id End_log_pos Info ...@@ -267,3 +267,40 @@ Log_name Pos Event_type Server_id End_log_pos Info
# # Gtid 1 # GTID #-#-# # # Gtid 1 # GTID #-#-#
# # Query 1 # use `test`; DROP EVENT IF EXISTS ev1 # # Query 1 # use `test`; DROP EVENT IF EXISTS ev1
RESET MASTER; 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;
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;
...@@ -6,8 +6,6 @@ INSERT INTO t2 VALUES(1),(2),(3); ...@@ -6,8 +6,6 @@ INSERT INTO t2 VALUES(1),(2),(3);
# #
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int); CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int);
ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS 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); create or replace table mysql.general_log (a int);
ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled
create or replace table mysql.slow_log (a int); create or replace table mysql.slow_log (a int);
......
...@@ -1957,6 +1957,8 @@ drop table if exists t1; ...@@ -1957,6 +1957,8 @@ drop table if exists t1;
create table t1 (i int, j int); 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;
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' 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;
drop trigger t1_bi; drop trigger t1_bi;
......
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
--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
...@@ -1622,12 +1622,18 @@ END ; | ...@@ -1622,12 +1622,18 @@ END ; |
INSERT INTO t1 (pk, int_key) SELECT `pk` , `int_key` FROM B ; INSERT INTO t1 (pk, int_key) SELECT `pk` , `int_key` FROM B ;
--delimiter | --delimiter |
--error ER_NOT_SUPPORTED_YET --error ER_TRG_ALREADY_EXISTS
CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW CREATE TRIGGER f BEFORE INSERT ON t1 FOR EACH ROW
BEGIN BEGIN
UPDATE A SET `pk`=1 WHERE `pk`=0 ; UPDATE A SET `pk`=1 WHERE `pk`=0 ;
END ;| 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 ; --delimiter ;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -127,6 +127,22 @@ CREATE OR REPLACE EVENT ev1 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE IF EXISTS t ...@@ -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; SELECT EVENT_NAME, EVENT_DEFINITION FROM INFORMATION_SCHEMA.EVENTS;
DROP EVENT ev1; DROP EVENT ev1;
DROP EVENT IF EXISTS 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_column 1 # 2 # 5 #
--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VER/ --replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VER/
SHOW BINLOG EVENTS; SHOW BINLOG EVENTS;
......
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;
...@@ -21,8 +21,6 @@ INSERT INTO t2 VALUES(1),(2),(3); ...@@ -21,8 +21,6 @@ INSERT INTO t2 VALUES(1),(2),(3);
--error ER_WRONG_USAGE --error ER_WRONG_USAGE
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int); 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 # check that we don't try to create a log table in use
--error ER_BAD_LOG_STATEMENT --error ER_BAD_LOG_STATEMENT
......
...@@ -2237,8 +2237,10 @@ drop table if exists t1; ...@@ -2237,8 +2237,10 @@ drop table if exists t1;
create table t1 (i int, j int); 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 ER_NOT_SUPPORTED_YET --error ER_TRG_ALREADY_EXISTS
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 ER_NOT_SUPPORTED_YET
create trigger t1_bi2 before insert on t1 for each row begin end;
drop trigger t1_bi; drop trigger t1_bi;
--error ER_TRG_DOES_NOT_EXIST --error ER_TRG_DOES_NOT_EXIST
drop trigger t1_bi; drop trigger t1_bi;
......
...@@ -608,6 +608,63 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) ...@@ -608,6 +608,63 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(result); 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. Create trigger for table.
...@@ -640,8 +697,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -640,8 +697,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN]; char file_buff[FN_REFLEN], trigname_buff[FN_REFLEN];
LEX_STRING file, trigname_file; LEX_STRING file, trigname_file;
LEX_STRING *trg_def; LEX_STRING *trg_def;
LEX_STRING definer_user;
LEX_STRING definer_host;
ulonglong *trg_sql_mode; ulonglong *trg_sql_mode;
char trg_definer_holder[USER_HOST_BUFF_SIZE]; char trg_definer_holder[USER_HOST_BUFF_SIZE];
LEX_STRING *trg_definer; LEX_STRING *trg_definer;
...@@ -650,6 +705,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -650,6 +705,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
LEX_STRING *trg_client_cs_name; LEX_STRING *trg_client_cs_name;
LEX_STRING *trg_connection_cl_name; LEX_STRING *trg_connection_cl_name;
LEX_STRING *trg_db_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()) if (check_for_broken_triggers())
return true; return true;
...@@ -659,20 +716,31 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -659,20 +716,31 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
lex->spname->m_db.str)) lex->spname->m_db.str))
{ {
my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); 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), my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"multiple triggers with the same action time" "multiple triggers with the same action time"
" and event for one table"); " and event for one table");
return 1; return true;
} }
if (sp_process_definer(thd)) if (sp_process_definer(thd))
return 1; return true;
/* /*
Let us check if all references to fields in old/new versions of row in 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, ...@@ -701,7 +769,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
if (!trg_field->fixed && if (!trg_field->fixed &&
trg_field->fix_fields(thd, (Item **)0)) 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, ...@@ -722,8 +790,29 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Use the filesystem to enforce trigger namespace constraints. */ /* Use the filesystem to enforce trigger namespace constraints. */
if (!access(trigname_buff, F_OK)) if (!access(trigname_buff, F_OK))
{ {
my_error(ER_TRG_ALREADY_EXISTS, MYF(0)); if (lex->create_info.or_replace())
return 1; {
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; trigname.trigger_table.str= tables->table_name;
...@@ -731,7 +820,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -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, if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
(uchar*)&trigname, trigname_file_parameters)) (uchar*)&trigname, trigname_file_parameters))
return 1; return true;
/* /*
Soon we will invalidate table object and thus Table_triggers_list object 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, ...@@ -764,29 +853,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
*trg_sql_mode= thd->variables.sql_mode; *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: Fill character set information:
- client character set contains charset info only; - client character set contains charset info only;
...@@ -802,30 +868,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -802,30 +868,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
lex_string_set(trg_db_cl_name, lex_string_set(trg_db_cl_name,
get_default_db_collation(thd, tables->db)->name); get_default_db_collation(thd, tables->db)->name);
/* build_trig_stmt_query(thd, tables, stmt_query,
Create well-formed trigger definition query. Original query is not trg_definer, trg_definer_holder);
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);
trg_def->str= stmt_query->c_ptr_safe(); trg_def->str= stmt_query->c_ptr_safe();
trg_def->length= stmt_query->length(); trg_def->length= stmt_query->length();
...@@ -834,11 +878,11 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, ...@@ -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, if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
(uchar*)this, triggers_file_parameters)) (uchar*)this, triggers_file_parameters))
return 0; return false;
err_with_cleanup: err_with_cleanup:
mysql_file_delete(key_file_trn, trigname_buff, MYF(MY_WME)); mysql_file_delete(key_file_trn, trigname_buff, MYF(MY_WME));
return 1; return true;
} }
......
...@@ -2560,20 +2560,6 @@ create: ...@@ -2560,20 +2560,6 @@ create:
Lex->create_view_suid= TRUE; Lex->create_view_suid= TRUE;
} }
view_or_trigger_or_sp_or_event 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 | create_or_replace USER opt_if_not_exists clear_privileges grant_list
{ {
if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3)) if (Lex->set_command_with_check(SQLCOM_CREATE_USER, $1 | $3))
...@@ -16159,23 +16145,28 @@ view_check_option: ...@@ -16159,23 +16145,28 @@ view_check_option:
trigger_tail: trigger_tail:
TRIGGER_SYM TRIGGER_SYM
remember_name remember_name
opt_if_not_exists
{
if (Lex->add_create_options_with_check($3))
MYSQL_YYABORT;
}
sp_name sp_name
trg_action_time trg_action_time
trg_event trg_event
ON ON
remember_name /* $7 */ remember_name /* $9 */
{ /* $8 */ { /* $10 */
Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start(); Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start();
} }
table_ident /* $9 */ table_ident /* $11 */
FOR_SYM FOR_SYM
remember_name /* $11 */ remember_name /* $13 */
{ /* $12 */ { /* $14 */
Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start(); Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start();
} }
EACH_SYM EACH_SYM
ROW_SYM ROW_SYM
{ /* $15 */ { /* $17 */
LEX *lex= thd->lex; LEX *lex= thd->lex;
Lex_input_stream *lip= YYLIP; Lex_input_stream *lip= YYLIP;
...@@ -16186,17 +16177,17 @@ trigger_tail: ...@@ -16186,17 +16177,17 @@ trigger_tail:
} }
lex->stmt_definition_begin= $2; lex->stmt_definition_begin= $2;
lex->ident.str= $7; lex->ident.str= $9;
lex->ident.length= $11 - $7; lex->ident.length= $13 - $9;
lex->spname= $3; lex->spname= $5;
if (!make_sp_head(thd, $3, TYPE_ENUM_TRIGGER)) if (!make_sp_head(thd, $5, TYPE_ENUM_TRIGGER))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
} }
sp_proc_stmt /* $16 */ sp_proc_stmt /* $18 */
{ /* $17 */ { /* $19 */
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
...@@ -16212,7 +16203,7 @@ trigger_tail: ...@@ -16212,7 +16203,7 @@ trigger_tail:
sp_proc_stmt alternatives are not saving/restoring LEX, so sp_proc_stmt alternatives are not saving/restoring LEX, so
lex->query_tables can be wiped out. 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, (LEX_STRING*) 0,
TL_OPTION_UPDATING, TL_OPTION_UPDATING,
TL_READ_NO_INSERT, TL_READ_NO_INSERT,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment